Authoring doc stories
The doc blocks from @unpunnyfuns/swatchbook-blocks are React components that render against the active token graph. Use them in MDX stories to compose a proper reference page — a ColorPalette, a TypographyScale, a TokenTable filtered to a subpath — all of which live-update as the toolbar changes axes.
Prerequisite
Install the blocks package:
npm install -D @unpunnyfuns/swatchbook-blocks
The blocks read the active token graph from a SwatchbookProvider. The addon's preview decorator mounts that provider for every story, so the blocks render inside MDX as long as @unpunnyfuns/swatchbook-addon is registered in your Storybook.
A minimal docs page
import { Meta } from '@storybook/addon-docs/blocks';
import { ColorPalette, TokenTable } from '@unpunnyfuns/swatchbook-blocks';
<Meta title="Docs/Colors" />
# Colors
Our color tokens live under a single flat namespace. Semantic slots like
`color.surface.default` carry mode- and brand-varied values through the
resolver, so components style themselves against `color.*` directly.
## Primitive palette
<ColorPalette filter="color.*" />
## Semantic slots
<TokenTable filter="color.*" type="color" />
Restart your Storybook dev server (if HMR doesn't pick up new MDX files) and visit Docs / Colors. The palette swatches and table values update live as you flip the toolbar.
Blocks at a glance
| Block | What it renders |
|---|---|
TokenDetail | A single token's full picture — alias chain, aliased-by tree, per-axis variance, composite preview. |
TokenTable | Filterable table of tokens. Supports path glob and $type filters. |
ColorPalette | Swatch grid grouped by sub-path. |
TypographyScale | Renders each typography-typed token as a sample line using its own value. |
FontFamilySample | Pangram rendered per fontFamily primitive. |
FontWeightScale | Same "Aa" sample at each fontWeight. |
StrokeStyleSample | Border rendered per strokeStyle primitive. |
| Motion / shadow / border previews | Inside TokenDetail's composite rendering. |
See Reference: blocks for the full prop surface.
Typed token access from components
If you're writing a component that needs a token's resolved value (not just a CSS var reference), use the useToken hook. It reads from the virtual graph + active axis tuple and returns { value, cssVar, type, description } with typed paths:
import { useToken } from '@unpunnyfuns/swatchbook-addon/hooks';
function Badge({ level }: { level: 'info' | 'warn' }) {
const tokenName = level === 'info' ? 'color.accent.bg' : 'color.warning.bg';
const bg = useToken(tokenName);
return <span style={{ background: bg.cssVar }}>{bg.description}</span>;
}
cssVar is stable across themes; value reflects the active tuple. Paths autocomplete from a generated .swatchbook/tokens.d.ts once the addon has run.
Overriding the axes on a specific doc
Force a specific tuple on a single doc page:
<Meta title="Docs/Colors (Dark)" parameters={{ swatchbook: { axes: { mode: 'Dark' } } }} />
The addon's toolbar still reflects the story's active tuple, so readers can tell what they're seeing. Any axis you omit falls back to its default.
What MDX can't do
Storybook's preview hooks (useGlobals, useArgs, useChannel) throw when called from an MDX doc block — the preview HooksContext only exists while a story is rendering. The blocks in this package avoid those by subscribing to Storybook's channel directly. If you write a custom block for your project, follow the same pattern:
import { addons } from 'storybook/preview-api';
const channel = addons.getChannel();
channel.on('globalsUpdated', (payload) => {
// react to axis / theme changes
});
See also
- Reference: blocks — every block's props.
- Reference: addon —
useTokenand the other hooks. - Live Storybook — real doc stories you can steal from.