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

SurfaceFile or settingScopeUse it for
Preview setup`.storybook/preview.tstsx`Every story in the preview
Preview head.storybook/preview-head.htmlThe preview iframe headStatic stylesheets, font files, and similar tags
Preview body.storybook/preview-body.htmlThe preview iframe bodyCustom content roots, portal targets, base font-size styles
Preset customizationPreset referenced from main.jsProgrammatic preview HTML customizationAddon or preset-driven UI configuration for preview head or body
Layoutparameters.layoutGlobal, component, or story presentationcentered, 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.