In this article, you'll learn how to integrate Storybook into an existing Next.js project, including support for different themes.
Introduction
Storybook is an open-source tool that allows developers to build, test, and document UI components in isolation.
Install storybook
To get started, initialize Storybook in your project:
npx storybook@latest init
Configure Your Project
Below is an example configuration for integrating Storybook with a Next.js project:
main.ts
// main.ts
import type { StorybookConfig } from '@storybook/nextjs'
import { join, dirname } from 'path'
function getAbsolutePath(value: string): any {
return dirname(require.resolve(join(value, 'package.json')))
}
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
getAbsolutePath('@storybook/addon-onboarding'),
getAbsolutePath('@storybook/addon-essentials'),
getAbsolutePath('@chromatic-com/storybook'),
getAbsolutePath('@storybook/addon-interactions'),
],
framework: {
name: '@storybook/nextjs',
options: {},
},
staticDirs: ['../public'],
}
export default config
preview.ts
// preview.ts
import { Preview } from '@storybook/react'
import { themesNames } from '../src/theme'
// Contexts providers
import { withThemeProvider } from './themeProvider'
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime'
export const globalTypes = {
parameters: {
nextRouter: {
Provider: RouterContext.Provider,
},
},
theme: {
name: 'Theme',
description: 'Global theme for components',
defaultValue: 'defaultTheme',
toolbar: {
icon: 'paintbrush',
items: themesNames,
showName: true,
},
}
}
const preview: Preview = {
decorators: [withThemeProvider],
}
export default preview
Note: When configuring Storybook with custom providers, such as themes or global contexts, it’s essential to mock these contexts properly.
Context Providers Setup
themeProvider.tsx
// themeProvider.tsx
import React from 'react'
import { ThemeProvider } from 'styled-components'
import { Decorator } from '@storybook/react'
import { QueryClient, QueryClientProvider } from 'react-query'
import { AppRouterContext } from 'next/dist/shared/lib/app-router-context.shared-runtime'
import { GlobalStyle } from '../src/styles/Global.styles'
const queryClient = new QueryClient()
const themes = {
// ... all project themes
// 'projectName' : { ...settings}
}
// Contexts providers
export const withThemeProvider: Decorator = (Story, context) => {
const selectedTheme = context.globals.theme ?? 'defaultTheme'
return (
<QueryClientProvider client={queryClient}>
<AppRouterContext.Provider
// Overriding nextjs router functions
value={{
push: async () => true,
replace: async () => true,
back: () => {},
prefetch: async () => {},
forward: () => {},
refresh: () => {},
}}
>
<ThemeProvider theme={themes[selectedTheme]}>
<GlobalStyle />
<Story />
</ThemeProvider>
</AppRouterContext.Provider>
</QueryClientProvider>
)
}
Example: Button Component
1. Create the Component
Create a new folder for the component at /src/components/button. Inside this folder, add the following file:
/src/components/button/index.tsx
// index.tsx
export default function Button({children, onClick, disabled}){
return <button onClick={onClick} disabled={disabled}>{children}</button>
}
2. Add Stories
In the same folder, create a file named Button.stories.ts to define the stories for the Button component.
You can use diferents files [js|jsx|mjs|ts|tsx].
/src/components/button/Button.stories.ts
// Button.stories.ts
import type { Meta, StoryObj } from '@storybook/react'
import { fn } from '@storybook/test'
import Button from './'
const meta = {
title: 'UI/Primary Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {},
args: { onClick: fn() },
} satisfies Meta<typeof Button>
export default meta
type Story = StoryObj<typeof meta>
export const Primary: Story = {
args: {
children: 'Button',
disabled: false,
},
parameters: {
nextjs: {
appDirectory: true,
},
},
}
export const Disabled: Story = {
args: {
children: 'Button Disabled',
disabled: true,
},
parameters: {
nextjs: {
appDirectory: true,
},
},
}
Run and Build Storybook
To build and run your Storybook environment, use the following commands:
Build Storybook:
npm run build-storybook
Run Storybook:
npm run storybook
Finally, you can view Storybook's UI by opening it in your browser. After running npm run storybook, Storybook will be accessible at:
http://localhost:6006
This interface allows you to browse, test, and document your components interactively. Enjoy exploring your UI components with Storybook! 🎉
Top comments (0)