Headless
Replace the UI of stories, or build your own on the headless layer.
Overview
@fumadocs/story/headless provides the state of a story, without UI:
- the selected variant, and the preset it resolves to
- the arguments of the rendered component, debounced so typing doesn't re-render it on every keystroke
The built-in panel is built on it, and you can swap the panel for your own.
Your own panel
defineStoryFactory() takes a WithControl component, rendered in place of the built-in panel.
import { defineStoryFactory } from '@fumadocs/story/vite/client';
import { StoryPanel } from '@/components/story-panel';
export const { defineStory } = defineStoryFactory({ WithControl: StoryPanel });It receives the presets of the story and the component to render.
'use client';
import {
StoryProvider,
useStory,
useStoryArgs,
type WithControlProps,
} from '@fumadocs/story/headless';
export function StoryPanel(props: WithControlProps) {
return (
<StoryProvider {...props}>
<Content />
</StoryProvider>
);
}
function Content() {
const { presets, variant, setVariant, preset, Component } = useStory();
const args = useStoryArgs();
return (
<div>
<select value={variant} onChange={(e) => setVariant(e.target.value)}>
{presets.map((item) => (
<option key={item.variant} value={item.variant}>
{item.variant}
</option>
))}
</select>
<Component {...args} />
<pre>{JSON.stringify(preset?.controls, null, 2)}</pre>
</div>
);
}| Hook | Description |
|---|---|
useStory() | The presets, the selected variant with setVariant, and the Component. |
useStoryArgs() | The arguments of the rendered component, following the controls. |
Controls are edited through @fumari/stf, the form engine <StoryProvider /> sets up. preset.controls is the type tree of the component props.
Start from the built-in panel
Writing a full control panel means handling every node kind of the type tree. Install the built-in one below and edit it instead.
Install the UI
The entire panel, including its argument controls:
npx @fumadocs/cli add fumadocs/story/controlsimport { defineStoryFactory } from '@fumadocs/story/vite/client';
import { WithControl } from '@/components/story';
export const { defineStory } = defineStoryFactory({ WithControl });How is this guide?
Last updated on
