Storybook Source Doc Block#
The Source block renders a syntax-highlighted code snippet in MDX-based documentation. Source code resolution follows a two-stage pipeline: a renderer-specific sourceDecorator captures the rendered output at story-render time and emits it to a shared context; the Source React component then reads that snippet and applies any overrides before display.
Code Selection (useCode)#
The useCode hook in Source.tsx selects what to display using this priority order:
parameters.docs.source.codeβ always wins if set- Dynamic snippet from
SourceContextβ used whentype === 'dynamic', or whentype === 'auto'and the story uses args parameters.docs.source.originalSourceβ static source injected by the CSF loader
The SourceProps type exposes of, type, transform, code, language, dark, and format. excludeDecorators is not listed, not consumed, and not forwarded by the component.
Renderer sourceDecorator Logic#
Whether decorators are stripped is determined inside each renderer's decorator, which reads parameters.docs.source.excludeDecorators from the story context β not from any JSX prop passed to <Source>.
- HTML β sourceDecorator.ts: when
excludeDecoratorsis truthy, callscontext.originalStoryFn(context.args, context)instead of the decoratedstoryresult . Otherwise, passes through the decorated output. - Web Components β identical pattern to HTML: checks
context.parameters.docs.source.excludeDecoratorsand swaps tocontext.originalStoryFn. - React (
jsxDecorator.tsx) β always callscontext.originalStoryFnto produce JSX source; effectively decorator-free by design, noexcludeDecoratorscheck. - Svelte β always calls
context.originalStoryFnto generate Svelte template source; also effectively decorator-free by design. - Vue 3 β generates source from
ctx.argsand__docgenInfowithout referencing the decorated render result; noexcludeDecoratorscheck.
The emitted snippet travels via emitTransformCode into SourceContext, which is then consumed by the Source block.
The excludeDecorators Documentation Gap#
The official docs list excludeDecorators as a <Source> block prop (type: boolean, default: parameters.docs.source.excludeDecorators). In practice, SourceProps never declares, reads, or forwards this prop β passing <Source of={MyStory} excludeDecorators={true} /> is silently ignored.
This is a confirmed documentation/implementation discrepancy as of Storybook 10.x.
Correct Usage: Story-Level Parameter#
Because excludeDecorators is only read by renderer decorators from the story's parameters, it must be set at the story level:
// Button.stories.ts
export const PrimaryWithoutDecorators = {
...Primary,
parameters: {
docs: {
source: {
excludeDecorators: true,
},
},
},
};
Reference both exports in MDX to get both variants:
<Source of={ButtonStories.Primary} /> {/* with decorators */}
<Source of={ButtonStories.PrimaryWithoutDecorators} /> {/* without decorators */}
Because excludeDecorators is story-scoped, two <Source> blocks pointing at the same story cannot independently toggle it. Use a second story export (as above), or use explicit code/transform props on one block.
Key Files#
| File | Purpose |
|---|---|
blocks/Source.tsx | Source React component, SourceProps type, useCode hook |
components/Source.tsx | Pure presentational Source component (syntax highlighter wrapper) |
html/src/docs/sourceDecorator.ts | HTML renderer β excludeDecorators implementation |
| Official Source block docs | Public API reference (note: excludeDecorators prop is documented but not implemented as a JSX prop) |