[Next.js] Storybook V7

[Next.js] Storybook V7

2023-05-29 hit count image

Let's see how to use Storybook V7 in Next.js based on TypeScript for Component Driven Development.

Outline

In this blog post, I will introduce how to use Storybook in Next.js with TypeScript for CDD(Component Driven Development).

In this blog post, I will use Storybook V7 version(next). If you want to know how to use the V6 version of Storybook, please see the following link.

You can see the full source code of thie blog post on the following link.

Create Next.js based on TypeScript

To use Storybook in Next.js with TypeScript, execute the following command to create a new Next.js project based on TypeScript.

npx create-next-app --typescript start-storybook-v7

Install Storybook

To use Storybook for CDD with Next.js based on TypeScript, we need to install Storybook. Execute the following command to install Storybook.

# cd start-storybook-v7
npm install --save-dev [email protected]

Initialize Storybook

To use Storybook, we need to initialize Storybook to install the required libraries. Execute the following command to initialize Storybook.

And then, you can see the Storybook is initialized automatically like the following.

  storybook init - the simplest way to add a Storybook to your project.

 • Detecting project type. ✓
 • Adding Storybook support to your "Next" app

added 318 packages, and audited 1125 packages in 54s

226 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
. ✓
 • Preparing to install dependencies. ✓

Lastly, you can see the following question.

? Do you want to run the 'eslintPlugin' migration on your project? › (Y/n)

If you want to use ESLint to check the code, press y. If not, press n. In this blog post, y is pressed.

After all, you can see Storybook installs all required libraries, and Storybook execution scripts is added automatically like the following.

Storybook V7 configuration automatically
{
   ...
   "scripts": {
    ...
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },
  ...
  "devDependencies": {
    "@storybook/addon-essentials": "^7.0.0-rc.8",
    "@storybook/addon-interactions": "^7.0.0-rc.8",
    "@storybook/addon-links": "^7.0.0-rc.8",
    "@storybook/blocks": "^7.0.0-rc.8",
    "@storybook/nextjs": "^7.0.0-rc.8",
    "@storybook/react": "^7.0.0-rc.8",
    "@storybook/testing-library": "^0.0.14-next.1",
    "eslint-plugin-storybook": "^0.6.11",
    "storybook": "^7.0.0-rc.8"
    ...
  }
}

Also, you can see the following folders are created for the sample code about how to use Storybook.

  • ./.storybook/...: Storybook configuration files.
  • ./stories/...: Storybook sample codes.

In this blog post, we decided to use ESLint, so when you open the .eslintrc.json file, you can see the following changes.

{
  "extends": [
    "next/core-web-vitals",
    "plugin:storybook/recommended"
  ]
}

Configure public folder

To make Storybook recognize the static files(images) in the public folder of Next.js, open the main.ts file and modify it like the following.

import type { StorybookConfig } from '@storybook/nextjs'
const config: StorybookConfig = {
  ...
  docs: {
    autodocs: 'tag',
  },
  staticDirs: ['../public'],
}
export default config

Execute Storybook

We’ve done all configurations of Storybook. Now, let’s see if the configuration and installation of Storybook are well by executing it. Execute the following command to run Storybook.

npm run storybook

And then, you can see the browser is automatically opened with http://localhost:6006/, and you can see the following screen on it.

Storybook V7 first screen

This screen shows the ./stories/Introduction.mdx file.

Check Storybook

When you click the Button > Primary on left menu of Storybook, you can see the screen like the following.

Storybook V7 button sample

This screen shows the ./stories/Button.stories.ts file.

Sample code details

Let’s see details of the sample code for seeing Storybook deeply. The Button component(./stories/Button.tsx) is like the following.

import React from 'react';
import './button.css';

interface ButtonProps {
  primary?: boolean;
  backgroundColor?: string;
  size?: 'small' | 'medium' | 'large';
  label: string;
  onClick?: () => void;
}

export const Button = ({
  primary = false,
  size = 'medium',
  backgroundColor,
  label,
  ...props
}: ButtonProps) => {
  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
  return (
    <button
      type="button"
      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
      {...props}
    >
      {label}
      <style jsx>{`
        button {
          background-color: ${backgroundColor};
        }
      `}</style>
    </button>
  );
};

You can see the Button component has various Props like primary, backgroundColor, and so on. Next, let’s check the Storybook file(./stories/Button.stories.ts).

import type { Meta, StoryObj } from '@storybook/react';

import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: {
      control: 'color',
    },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary: Story = {
  args: {
    label: 'Button',
  },
};

export const Large: Story = {
  args: {
    size: 'large',
    label: 'Button',
  },
};

export const Small: Story = {
  args: {
    size: 'small',
    label: 'Button',
  },
};

First, prepare the necessary information to compose the screen of Storybook.

import type { Meta, StoryObj } from '@storybook/react';

import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: {
      control: 'color',
    },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;
...

You can configure the basic information to display in Storybook. The title set in meta indicates the name to be displayed on the left menu of Storybook, and you can create a group through / in it. In the sample code, you can see that the name Button is displayed under the Example group.

Storybook V7 meta information

component in meta specifies the component to display in this Storybook. In the sample code, the Button component is specified.

tags: ['autodocs'] is a new feature that creates documents automatically. If you set this value, you can see that Docs is automatically created under the Example/Button menu as shown in the screenshot above, and you can see the contents written in the Storybook file in the form of a document.

If you configure the necessary information for the screen, you need to create a Story that will actually be displayed on the screen for the next step. You can create a Story with setting or changing the Props of the component as follows.

...
export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary: Story = {
  args: {
    label: 'Button',
  },
};

export const Large: Story = {
  args: {
    size: 'large',
    label: 'Button',
  },
};

export const Small: Story = {
  args: {
    size: 'small',
    label: 'Button',
  },
};

Configure Storybook

Currently, we can only create Storybook files in the ./stories folder. However, normally the components are created and managed in the ./components folder.

So, to be able to create the Storybook files in other folders, you need to modify the ./.storybook/main.ts file. Open the ./.storybook/main.ts file and modify it like the following.

import type { StorybookConfig } from '@storybook/nextjs';
const config: StorybookConfig = {
  stories: [
    '../@(stories|components)/**/*.mdx',
    '../@(stories|components)/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  ...
};
...

Now, if you have a file name of .stories.ts in the components folder in addition to the stories folder, Storybook will recognize it and display it on the screen. To check this, create the ./components/SampleButton folder and copy the following files.

  • ./stories/button.css > ./components/SampleButton/index.css
  • ./stories/Button.stories.ts > ./components/SampleButton/index.stories.ts
  • ./stories/Button.tsx > ./components/SampleButton/index.tsx

And, open the ./components/SampleButton/index.tsx file and modify it like the following.

...
import './index.css';
...
export const SampleButton = ({
   ...
}: ButtonProps) => {
   ...
};

Also, open the ./components/SampleButton/index.stories.ts file and modify it like the following.

...
import { SampleButton } from '.';

const meta: Meta<typeof SampleButton> = {
  title: 'Sample/Button',
  component: SampleButton,
  ...
};

export default meta;
type Story = StoryObj<typeof SampleButton>;
...

Since we have changed the setting of Storybook, to apply it, terminate the currently running Storybook and run it again. WhenStorybook is executed again, you can see the SampleButton is shown well like the following.

Storybook V7 SampleButton

Completed

Done! we’ve seen how to install and configure Storybook V7 in Next.js with TypeScript for CDD. And compared to the previous version, I think it has become much more convenient and more intuitive. If you want to know how to use the previous version of Storybook, please check the following link.

Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!

App promotion

You can use the applications that are created by this blog writer Deku.
Deku created the applications with Flutter.

If you have interested, please try to download them for free.

Posts