Story Rendering and Layout
Purpose and Scope
Story rendering is the part of Storybook that turns a selected story into visible UI inside the Canvas. The Storybook application itself surrounds that Canvas with navigation, panels, and toolbars, but the story is rendered in a separate preview iframe. That distinction matters because JavaScript build behavior, global setup code, static tags, and layout choices affect the preview environment rather than the manager UI. Use this page when a component needs global CSS, a library must be initialized before rendering, HTML must be injected around stories, or the Canvas positioning needs to be made predictable across stories.
Sources: docs/configure/story-rendering.mdx
The rendering configuration described here sits between two larger concerns. Builder configuration controls the JavaScript build for the preview, while the preview configuration and preview HTML files control what runs or appears in the iframe where components render. Storybook’s documentation explicitly separates those concerns so teams can avoid solving runtime setup problems in the wrong layer. If a component fails because a provider, stylesheet, icon registry, localization package, or DOM root is absent, start with the preview surfaces described below before changing the application shell or unrelated build settings.
Sources: docs/configure/story-rendering.mdx
Relevant Source Files
docs/configure/story-rendering.mdx— Defines the public Storybook docs page for preview iframe rendering, code that runs for every story, preview head injection, preview body injection, and preset-based HTML customization.
Core Rendering Surfaces
The most important runtime surface is .storybook/preview.ts|tsx. Code in this file executes for every story in the Storybook, which makes it the right place to establish shared rendering prerequisites. Typical examples include importing global styles, initializing libraries, or performing setup required before components mount. Because this runs in the preview context, it should be treated as story-environment setup rather than product application bootstrap. Keep this file focused on requirements that every story needs, and prefer story, component, or global decorators when setup must wrap rendering rather than merely run before it.
Sources: docs/configure/story-rendering.mdx
Renderer-specific projects may need a slightly different shape even when the intent is the same. The docs call out Vue and Angular as cases where the framework integration can change how global libraries are registered. A Vue project can extend Storybook’s application and register a library such as Font Awesome, while an Angular project may need a package such as localization added through polyfills.ts and imported there. The practical rule is to put cross-story setup where the renderer expects application-level setup, but still scope the change to the Storybook preview environment.
Sources: docs/configure/story-rendering.mdx
Preview HTML Injection
Use .storybook/preview-head.html when the preview iframe needs tags in its head. This is appropriate for static stylesheets, font files, and similar resources that must be present before stories render but do not belong in the Storybook manager UI. Storybook injects those tags into the preview iframe, not into the surrounding web application. That means a font face, stylesheet, meta tag, or script added this way affects components shown in the Canvas while leaving the sidebar, toolbar, and addon panels governed by Storybook’s own application environment.
Sources: docs/configure/story-rendering.mdx
Use .storybook/preview-body.html when the preview iframe needs additional body content. The docs describe this as useful for custom content roots, which is common when a component library expects a modal root, portal target, tooltip container, or similar element to exist beside the rendered story. The same body file can also contain a style tag for base sizing changes, such as adjusting root font size when a project relies on relative units like rem or em. As with head injection, the change is scoped to the preview iframe where components render.
Sources: docs/configure/story-rendering.mdx
Layout Parameters
Story layout controls how the rendered story is positioned inside the Canvas. The official Storybook layout guidance uses the layout parameter and supports applying it globally from .storybook/preview.ts|tsx, then overriding at narrower scopes when a component or individual story needs a different presentation. This keeps broad defaults simple while preserving escape hatches for pages, full-screen flows, or small components that are easier to inspect when centered. In practice, choose a global default that matches most components, then override only the outliers so the sidebar remains predictable and story authors do not duplicate layout boilerplate.
// .storybook/preview.ts
import type { Preview } from '@storybook/your-framework';
const preview: Preview = {
parameters: {
layout: 'centered',
},
};
export default preview;Common layout choices are centered, fullscreen, and padded. Use centered for isolated atoms and molecules that benefit from being placed in the middle of the Canvas. Use fullscreen for screens, routed pages, app shells, or components that already own their spacing and viewport assumptions. Use padded when the component should appear with ordinary Canvas breathing room but does not need centering. Layout is not a substitute for component styling; it is a Storybook presentation setting that helps reviewers see the same component state under a clear and repeatable frame.
Execution Flow
A useful mental model is that builder configuration first produces the preview bundle, then the preview environment prepares the iframe, then Storybook renders the selected story. The repository docs state that the preview iframe is where stories render and that the builder controls the preview’s JavaScript build configuration. After that build-level concern, .storybook/preview.ts|tsx runs shared setup for every story, preview head and body files contribute static HTML to the iframe, and the story itself renders into the Canvas. Layout parameters then determine how the story is positioned within that Canvas.
Sources: docs/configure/story-rendering.mdx
When debugging rendering problems, follow that sequence instead of changing everything at once. If a dependency is missing before stories mount, inspect the preview file or renderer-specific application setup. If CSS, fonts, or root elements are absent, inspect preview-head.html and preview-body.html. If the component renders but appears clipped, stretched, or awkwardly placed, inspect the layout parameter at the global, component, and story levels. If the preview iframe is correct but the surrounding Storybook UI is affected, the configuration probably belongs somewhere else because these rendering hooks are intentionally scoped to the preview iframe.
Sources: docs/configure/story-rendering.mdx
Compact Reference
| Surface | File or setting | Scope | Use it for |
|---|---|---|---|
| Preview setup | `.storybook/preview.ts | tsx` | Every story in the preview |
| Preview head | .storybook/preview-head.html | The preview iframe head | Static stylesheets, font files, and similar tags |
| Preview body | .storybook/preview-body.html | The preview iframe body | Custom content roots, portal targets, base font-size styles |
| Preset customization | Preset referenced from main.js | Programmatic preview HTML customization | Addon or preset-driven UI configuration for preview head or body |
| Layout | parameters.layout | Global, component, or story presentation | centered, fullscreen, or padded Canvas positioning |
Next Steps
Start with a small global default in .storybook/preview.ts|tsx, then add only the preview HTML files your component library actually requires. Keep injected tags minimal and remember that they target the preview iframe, not the Storybook application UI. For reusable wrapping behavior, continue to the decorators guide; for configurable per-story rendering behavior, continue to parameters; and for CSS, fonts, assets, and theme setup, read the styling and static assets configuration page. This sequence keeps rendering setup understandable and prevents global preview configuration from becoming a catch-all for unrelated application concerns.