Configure next/font with Tailwind in Storybook

Configure next/font with Tailwind in Storybook

·

2 min read

Next.js has font optimization option using their package next/font using google fonts and local. When adding a storybook to a Next.js project, you will start to wonder on how we can achieve the same font to be loaded into the storybook itself as well.

To solve this

We can reuse next/font that we use in the app/layout.tsx in our storybook configuration. To do this, we need to create another file and export the font from there to be used in our app/layout.tsx and our storybook configuration.

// app/font.ts

// Pick your font family that you want
import { Mukta, PT_Serif } from 'next/font/google';

export const fontSerif = PT_Serif({
  subsets: ['latin'],
  weight: ['400', '700'],
  variable: '--font-serif',
  display: 'swap'
});

export const fontSans = Mukta({
  subsets: ['latin'],
  weight: ['300', '400', '500', '700'],
  variable: '--font-sans',
  display: 'swap'
});

In the .storybook/preview.tsx , we just need to create a decorator that will inject our variable class using useEffect so that it is applied in the body, not just in the iframe of our story.

// .storybook/preview.tsx
import { fontSans, fontSerif } from '@/app/font';
import type { Preview } from '@storybook/react';

const preview = {
  decorators: [
    (Story) => {
      useEffect(() => {
        document.body.classList.add(
          fontSans.variable,
          fontSerif.variable,
          'font-sans',
          'antialiased'
        );
      }, []);

      return (
        <TooltipProvider>
          <Story />
        </TooltipProvider>
      );
    }
  ],
} satisfies Preview;

export default preview;

Why do we do this? The reason is if we do add the font class in a div and have the <Story /> as the children - it will not work for Dialog / Modal component that injects itself in a Portal as sibling of the storybook iframe - hence our font will not be applied.

Since Shadcn UI has been mostly a popular option for many frontend developers to be used and their Dialog component is using Radix UI which is injecting element into the Portal as sibling of the iframe.

Now after adding this decorator, you should see the body has the class added as well as the font updated.

Cheers!