Fumadocs

Vite

Configure Fumadocs Story for Vite-based frameworks.

Installation

npm i @fumadocs/story ts-morph

Add the Tailwind CSS preset.

Tailwind CSS
@import '@fumadocs/story/css/preset.css';

Externalize ts-morph:

vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  resolve: {
    external: ['ts-morph'],
  },
});

Create a Story

Create a story factory to store your global settings:

lib/story.ts
import { createFileSystemCache, defineStoryFactory } from '@fumadocs/story';

export const { defineStory, getStoryPayloads } = defineStoryFactory({
  // for Vercel, this is required: choose a directory for cache.
  cache: process.env.NODE_ENV === 'production' ? createFileSystemCache('.story/cache') : undefined,

  tsc: {
    // we use tsc to generate controls from types
    // you can pass TypeScript options here
  },
});

Now create your first story:

import { defineStory } from '@/lib/story';
import type { MyComponent } from './my-component';

// must be exported as `story`
// or set the `name` option to match export name.
export const story = defineStory<typeof MyComponent>(
  // the path of this file:
  'src/components/my-component.story.tsx',
  {
    args: {
      // default props (recommended)
      initial: {},
    },
  },
);

Story clients require payloads from server to render, you can leverage the SSR functionality of your React.js framework.

For instance, on Tanstack Start:

docs/$.tsx
import { story as calloutStory } from '@/components/my-component.story';
import { storyClient as calloutStoryClient } from '@/components/my-component.story.client';
import { StoryPayloadProvider } from '@fumadocs/story/client';
import { getStoryPayloads } from '@/lib/story';

export const Route = createFileRoute('/docs/$')({
  component: Page,
  loader: async ({ params }) => {
    // load story payloads from server
    return serverStoryLoader();
  },
});

const stories = {
  callout: calloutStory,
};

const clientStories = {
  callout: calloutStoryClient,
};

const serverStoryLoader = createServerFn({
  method: 'GET',
}).handler(async () => {
  return {
    // generate payloads
    storyPayloads: await getStoryPayloads(stories),
  };
});

function Page() {
  const data = Route.useLoaderData();

  return (
    <StoryPayloadProvider payloads={data.storyPayloads} clients={clientStories}>
      {/* children */}
    </StoryPayloadProvider>
  );
}

Now you can render the story like:

index.mdx
import { StoryWithControl } from '@fumadocs/story/client';

<StoryWithControl name="callout" />

Or from the story client instance:

index.mdx
import { storyClient } from '@/components/my-component.story.client';

<storyClient.WithControl />

How is this guide?

Last updated on

On this page