Decorators
Purpose and Scope
A decorator is Storybook’s mechanism for wrapping a story with extra rendering behavior before the story appears in the preview. In day-to-day story authoring, use decorators when the component is correct but the isolated rendering environment is incomplete: the story needs spacing, a page shell, a provider, a theme, mocked context, or addon behavior around it. The decorators documentation defines this as wrapping stories in extra “rendering” functionality, and notes that addons also use decorators to augment stories or gather information about how a story renders.
Sources: docs/writing-stories/decorators.mdx
Decorators solve a different problem from story args. Args model the inputs of a component state; decorators model the environment around that state. For example, a button story should usually keep its label, variant, and disabled state in args, while a decorator can add a padded wrapper so the button is not flush against the Canvas edge. That separation keeps stories portable and readable: the story still describes the component state, and the decorator describes the rendering harness needed to make that state useful inside Storybook.
Sources: docs/writing-stories/decorators.mdx
Relevant Source Files
docs/writing-stories/decorators.mdx— the first-party documentation page that defines decorators, shows the extra-markup use case, documents the decorator context object, and calls out renderer-specific behavior for Svelte and Vue.
Where Decorators Apply
Storybook decorators can be applied at multiple scopes. Use a global decorator in .storybook/preview when every story needs the same app-level shell, such as a theme provider, router, localization provider, or global CSS container. Use a component-level decorator in the component’s CSF file when all stories for that component need the same harness, such as margin around a component that otherwise touches the edge of the preview. Use a story-level decorator when only one state needs special setup, for example a single scenario that must be rendered in a constrained layout or a particular mocked context.
Sources: docs/writing-stories/decorators.mdx
The documentation’s first example focuses on component-level spacing because it is the easiest way to see the distinction. Some components only make sense when surrounded by layout markup. Rather than adding wrapper markup inside every story implementation, the decorator supplies the harness once and Storybook renders each story through it. This keeps the individual named story exports focused on component state while still producing a realistic preview. If the concern is only Storybook’s built-in Canvas positioning, also consider the story layout parameter; decorators are the more general tool when you need actual markup or providers around the story.
Sources: docs/writing-stories/decorators.mdx
Decorator Function Contract
A decorator function receives the story to render and, as its second argument, the story context. The context is important because it lets the wrapper react to the same metadata that Storybook uses to render and document the story. The documented context fields are args, argTypes, globals, hooks, parameters, and viewMode. Together they let a decorator read the current story inputs, Storybook-wide global values, static metadata, and the active window mode such as Canvas or Docs.
Sources: docs/writing-stories/decorators.mdx
The most common pattern is to call the story function inside a wrapper and return the resulting rendered output in the shape expected by the active renderer. For React-like renderers this is often a component wrapper; for other renderers the returned value follows that renderer’s integration contract. The decorators page calls out Svelte separately: a Svelte decorator can be implemented as a component, and when props must be passed to that component the decorator can return an object with Component and props keys. That renderer-specific detail matters because decorators are portable as a concept, but not always identical as return values across frameworks.
Sources: docs/writing-stories/decorators.mdx
Context for Mocking and Dynamic Layout
The story context is what turns decorators from static wrappers into configurable infrastructure. The page’s context section explains that decorators can adjust behavior based on args or metadata, including a documented pattern where a decorator reads parameters.pageLayout and conditionally applies a page-like or mobile-page layout. This is useful for application shells, route mocks, design-system containers, and test fixtures where the story author should be able to opt into a rendering mode without rewriting the wrapper for every story.
Sources: docs/writing-stories/decorators.mdx
Globals are especially useful when decorators provide cross-cutting context. Storybook-wide globals can be changed through toolbar controls, so a decorator can read the active theme, locale, color scheme, feature flag, or viewport-like mode and provide it to the component tree. The docs also note that Storybook API hooks such as useArgs and useGlobals are available in decorators and story render functions. When mixing Storybook hooks with framework hooks in a render function, use Storybook’s hook equivalents from storybook/preview-api to avoid re-render errors.
Sources: docs/writing-stories/decorators.mdx
Compact Reference
| Surface | Use it for | Notes |
|---|---|---|
Global decorators in preview configuration | App-wide providers, global layout shells, theme or locale context | Applies to all stories unless overridden by more specific behavior |
Component-level decorators in a CSF default export | Shared harness for every story of one component | The docs’ spacing example fits this scope |
Story-level decorators on a named story export | One scenario that needs unique rendering setup | Keep it narrow so the story remains easy to understand |
| Decorator second argument | Reading story context | Includes args, argTypes, globals, hooks, parameters, and viewMode |
| Svelte decorator return object | Passing props into a decorator component | Return an object with Component and props when needed |
A minimal mental model for authoring is: keep component state in the story, keep environment in the decorator, and keep reusable choices in context fields. If a wrapper only provides visual spacing for one component’s examples, define it near that component’s stories. If it supplies application infrastructure, define it globally so every story runs inside the same assumptions. If it needs to change per story, read parameters or globals from the context rather than duplicating wrapper variants.
Sources: docs/writing-stories/decorators.mdx
Implementation Details and Renderer Notes
Decorators participate in the same rendering pipeline that produces the isolated preview iframe shown when a story is selected. The story itself still represents a discrete component state, but Storybook invokes the configured decorators around that story before displaying it. Addons can also define decorators, which is why decorators are not just a documentation convenience; they are part of the extension model that lets Storybook features observe or enhance rendered stories without changing every story file.
Sources: docs/writing-stories/decorators.mdx
Renderer differences should be handled deliberately. The Svelte documentation path recommends creating a Svelte component to act as the decorator, then referencing that component from the story so it can wrap the rendered story with spacing or layout elements. The same section explains how to pass props into that decorator component. The Vue section calls out reactive globals and indicates that globals should pass through setup so decorator behavior remains reactive. These notes are reminders to follow the renderer integration rather than copying a decorator shape blindly from another framework.
Sources: docs/writing-stories/decorators.mdx
Authoring Checklist and Next Steps
Before adding a decorator, decide whether the requirement is truly environmental. Use args for component inputs, parameters for static Storybook or addon metadata, globals for toolbar-driven cross-story values, and decorators for the wrapper that consumes those values. Prefer the narrowest scope that expresses the requirement: story-level for one special case, component-level for a component harness, and global for app-wide providers. When a decorator becomes configurable, document the expected parameter or global name so future stories can opt in without reading the wrapper implementation first.
Sources: docs/writing-stories/decorators.mdx
Next, read the pages on Args and Arg Types to understand story inputs, Parameters to understand static metadata consumed by decorators and addons, Toolbars and Globals for UI-controlled global values, and Story Rendering and Layout for cases where built-in layout configuration is enough without a custom wrapper.