Skip to main content

Command Palette

Search for a command to run...

Configure next/font with Tailwind in Storybook

Updated
2 min read
Configure next/font with Tailwind in Storybook
B

Tinkering projects by Night. Working as a Frontend developer by Day. Frontend enthusiast.

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!

A

Hi Borris, thanks for this very nice blog post! If I may suggest a simple improvement, since this decorator is run before rendering each Story, you can add, out of the preview scope, a boolean variable that becomes true once the classes have been added to the body. You can then check the value of this variable on subsequent runs of the decorator and return early if the classes have already been added. Even if the cost of a classList.add isn't that important, this would help your technique scale better as the number of Stories grows.

1
B
Borris1y ago

Definitely interesting idea, will definitely try it out. The story rendering part should be isolated, so it should be new afresh on every story - hence I will have to check if the class is being reset or not on each story rendering. Thanks for the suggestion - will keep up to date with this as well after trying it out.

1
B
Borris1y ago

As simple as that to configure the next/font with your storybook

1

More from this blog

Borris Trendy Wiria Blog

8 posts

Sharing is caring, and I want to give to the community and share my knowledge around as a remainder that I learnt from the community as well.