diff --git a/docs/_snippets/nextjs-add-framework.md b/docs/_snippets/nextjs-add-framework.md index 1c87e051035a..011399eac75e 100644 --- a/docs/_snippets/nextjs-add-framework.md +++ b/docs/_snippets/nextjs-add-framework.md @@ -1,43 +1,44 @@ -```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF 3" +```diff filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF 3" export default { // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs', }; ``` -```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF 3" -import type { StorybookConfig } from '@storybook/nextjs'; +```diff filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF 3" +- import type { StorybookConfig } from '@storybook/your-previous-framework'; ++ import type { StorybookConfig } from '@storybook/nextjs'; const config: StorybookConfig = { // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs', }; export default config; ``` -```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) -import { defineMain } from '@storybook/your-framework/node'; +```diff filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" +- import { defineMain } from '@storybook/your-previous-framework/node'; ++ import { defineMain } from '@storybook/nextjs/node'; export default defineMain({ // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs', }); ``` -```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) -import { defineMain } from '@storybook/your-framework/node'; +```diff filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" +- import { defineMain } from '@storybook/your-previous-framework/node'; ++ import { defineMain } from '@storybook/nextjs/node'; export default defineMain({ // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs', }); ``` diff --git a/docs/_snippets/nextjs-app-directory-in-preview.md b/docs/_snippets/nextjs-app-directory-in-preview.md index 8ecf8d79e6e9..1b9b7ac6c05c 100644 --- a/docs/_snippets/nextjs-app-directory-in-preview.md +++ b/docs/_snippets/nextjs-app-directory-in-preview.md @@ -28,7 +28,7 @@ export default preview; ``` ```ts filename=".storybook/preview.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { definePreview } from '@storybook/your-framework'; export default definePreview({ @@ -45,7 +45,7 @@ export default definePreview({ ```js filename=".storybook/preview.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { definePreview } from '@storybook/your-framework'; export default definePreview({ diff --git a/docs/_snippets/nextjs-configure-svgr.md b/docs/_snippets/nextjs-configure-svgr.md index 332b6fc078aa..8b471f318893 100644 --- a/docs/_snippets/nextjs-configure-svgr.md +++ b/docs/_snippets/nextjs-configure-svgr.md @@ -53,7 +53,7 @@ export default config; ``` ```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ @@ -83,7 +83,7 @@ export default defineMain({ ```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ diff --git a/docs/_snippets/nextjs-image-static-dirs.md b/docs/_snippets/nextjs-image-static-dirs.md index af077340e6e3..8bb085e50fa6 100644 --- a/docs/_snippets/nextjs-image-static-dirs.md +++ b/docs/_snippets/nextjs-image-static-dirs.md @@ -28,7 +28,7 @@ export default config; ``` ```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ @@ -45,7 +45,7 @@ export default defineMain({ ```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ diff --git a/docs/_snippets/nextjs-remove-addons.md b/docs/_snippets/nextjs-remove-addons.md index 065a5d713d1f..fb08932d0173 100644 --- a/docs/_snippets/nextjs-remove-addons.md +++ b/docs/_snippets/nextjs-remove-addons.md @@ -11,7 +11,8 @@ export default { ``` ```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF 3" -import type { StorybookConfig } from '@storybook/nextjs'; +// Replace your-framework with nextjs or nextjs-vite +import type { StorybookConfig } from '@storybook/your-framework'; const config: StorybookConfig = { // ... @@ -27,7 +28,7 @@ export default config; ``` ```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ @@ -44,7 +45,7 @@ export default defineMain({ ```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ diff --git a/docs/_snippets/nextjs-vite-add-framework.md b/docs/_snippets/nextjs-vite-add-framework.md index 137479e97e3d..32b50f024ce7 100644 --- a/docs/_snippets/nextjs-vite-add-framework.md +++ b/docs/_snippets/nextjs-vite-add-framework.md @@ -1,43 +1,44 @@ -```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF 3" +```diff filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF 3" export default { // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs-vite', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs-vite', }; ``` -```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF 3" -import type { StorybookConfig } from '@storybook/nextjs-vite'; +```diff filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF 3" +- import type { StorybookConfig } from '@storybook/your-previous-framework'; ++ import type { StorybookConfig } from '@storybook/nextjs-vite'; const config: StorybookConfig = { // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs-vite', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs-vite', }; export default config; ``` -```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) -import { defineMain } from '@storybook/your-framework/node'; +```diff filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" +- import { defineMain } from '@storybook/your-previous-framework/node'; ++ import { defineMain } from '@storybook/nextjs-vite/node'; export default defineMain({ // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs-vite', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs-vite', }); ``` -```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) -import { defineMain } from '@storybook/your-framework/node'; +```diff filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" +- import { defineMain } from '@storybook/your-previous-framework/node'; ++ import { defineMain } from '@storybook/nextjs-vite/node'; export default defineMain({ // ... - // framework: '@storybook/react-webpack5', πŸ‘ˆ Remove this - framework: '@storybook/nextjs-vite', // πŸ‘ˆ Add this +- framework: '@storybook/react-webpack5', ++ framework: '@storybook/nextjs-vite', }); ``` diff --git a/docs/_snippets/nextjs-vite-remove-addons.md b/docs/_snippets/nextjs-vite-remove-addons.md deleted file mode 100644 index 0a28992d16bd..000000000000 --- a/docs/_snippets/nextjs-vite-remove-addons.md +++ /dev/null @@ -1,59 +0,0 @@ -```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF 3" -export default { - // ... - addons: [ - // ... - // πŸ‘‡ These can both be removed - // 'storybook-addon-next', - // 'storybook-addon-next-router', - ], -}; -``` - -```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF 3" -import type { StorybookConfig } from '@storybook/nextjs-vite'; - -const config: StorybookConfig = { - // ... - addons: [ - // ... - // πŸ‘‡ These can both be removed - // 'storybook-addon-next', - // 'storybook-addon-next-router', - ], -}; - -export default config; -``` - -```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) -import { defineMain } from '@storybook/your-framework/node'; - -export default defineMain({ - // ... - addons: [ - // ... - // πŸ‘‡ These can both be removed - // 'storybook-addon-next', - // 'storybook-addon-next-router', - ], -}); -``` - - - -```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) -import { defineMain } from '@storybook/your-framework/node'; - -export default defineMain({ - // ... - addons: [ - // ... - // πŸ‘‡ These can both be removed - // 'storybook-addon-next', - // 'storybook-addon-next-router', - ], -}); -``` diff --git a/docs/_snippets/rsc-feature-flag.md b/docs/_snippets/rsc-feature-flag.md index 1084b10054c7..438c6a6428d3 100644 --- a/docs/_snippets/rsc-feature-flag.md +++ b/docs/_snippets/rsc-feature-flag.md @@ -22,7 +22,7 @@ export default config; ``` ```ts filename=".storybook/main.ts" renderer="react" language="ts" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ @@ -36,7 +36,7 @@ export default defineMain({ ```js filename=".storybook/main.js" renderer="react" language="js" tabTitle="CSF Next πŸ§ͺ" -// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) +// Replace your-framework with nextjs or nextjs-vite import { defineMain } from '@storybook/your-framework/node'; export default defineMain({ diff --git a/docs/api/cli-options.mdx b/docs/api/cli-options.mdx index 6890686804ce..f33b476e0f38 100644 --- a/docs/api/cli-options.mdx +++ b/docs/api/cli-options.mdx @@ -123,13 +123,15 @@ Options include: | `-s`, `--skip-install` | Skips the dependency installation step. Used only when you need to configure Storybook manually.
`storybook init --skip-install` | | `-t`, `--type` | Defines the [framework](../configure/integration/frameworks.mdx) to use for your Storybook instance.
`storybook init --type solid` | | `-y`, `--yes` | Skips interactive prompts and automatically installs Storybook per specified version, including all features.
`storybook init --yes` | -| `--features [...values]` | Use these features when installing, skipping the prompt. Supported values are `docs`, `test` and `a11y`, space separated.
`storybook init --features docs test a11y` | +| `--features [...values]` | Use these features when installing, skipping the prompt. Supported values are `docs`, `test`, and `a11y`, space separated.
`storybook init --features docs test a11y` | | `--package-manager` | Sets the package manager to use when installing Storybook.
Available package managers include `npm`, `yarn`, and `pnpm`.
`storybook init --package-manager pnpm` | | `--use-pnp` | Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager.
`storybook init --use-pnp` | | `-p`, `--parser` | Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser).
Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`.
`storybook init --parser tsx` | | `--debug` | Outputs more logs in the CLI to assist debugging.
`storybook init --debug` | | `--disable-telemetry` | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).
`storybook init --disable-telemetry` | | `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).
`storybook init --enable-crash-reports` | +| `--loglevel ` | Controls level of logging during initialization.
Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`
`storybook init --loglevel debug` | +| `--logfile [path]` | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.
`storybook init --logfile /tmp/debug-storybook.log` | | `--no-dev` | Complete the initialization of Storybook without running the Storybook dev server.
`storybook init --no-dev` | ### `add` @@ -149,6 +151,8 @@ Options include: | `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`.
`storybook add [addon] --package-manager pnpm` | | `-s`, `--skip-postinstall` | Skips post-install configuration. Used only when you need to configure the addon yourself.
`storybook add [addon] --skip-postinstall` | | `--debug` | Outputs more logs in the CLI to assist debugging.
`storybook add --debug` | +| `--loglevel ` | Controls level of logging during addon installation.
Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`
`storybook add [addon] --loglevel debug` | +| `--logfile [path]` | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.
`storybook add [addon] --logfile /tmp/debug-storybook.log` | ### `remove` @@ -366,11 +370,13 @@ Options include: | `-s`, `--skip-install` | Skips the dependency installation step. Used only when you need to configure Storybook manually.
`create storybook --skip-install` | | `-t`, `--type` | Defines the [framework](../configure/integration/frameworks.mdx) to use for your Storybook instance.
`create storybook --type solid` | | `-y`, `--yes` | Skips interactive prompts and automatically installs Storybook per specified version, including all features.
`create storybook --yes` | -| `--features [...values]` | Use these features when installing, skipping the prompt. Supported values are `docs`, `test` and `a11y`, space separated.
`create storybook --features docs test a11y` | +| `--features [...values]` | Use these features when installing, skipping the prompt. Supported values are `docs`, `test`, and `a11y`, space separated.
`create storybook --features docs test a11y` | | `--package-manager` | Sets the package manager to use when installing Storybook.
Available package managers include `npm`, `yarn`, and `pnpm`.
`create storybook --package-manager pnpm` | | `--use-pnp` | Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager.
`create storybook --use-pnp` | | `-p`, `--parser` | Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser).
Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`.
`create storybook --parser tsx` | | `--debug` | Outputs more logs in the CLI to assist debugging.
`create storybook --debug` | | `--disable-telemetry` | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).
`create storybook --disable-telemetry` | | `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).
`create storybook --enable-crash-reports` | +| `--loglevel ` | Controls level of logging during initialization.
Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`
`storybook init --loglevel debug` | +| `--logfile [path]` | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.
`storybook init --logfile /tmp/debug-storybook.log` | | `--no-dev` | Complete the initialization of Storybook without running the Storybook dev server.
`create storybook --no-dev` | diff --git a/docs/get-started/frameworks/nextjs-vite.mdx b/docs/get-started/frameworks/nextjs-vite.mdx new file mode 100644 index 000000000000..12b66b6329b0 --- /dev/null +++ b/docs/get-started/frameworks/nextjs-vite.mdx @@ -0,0 +1,954 @@ +--- +title: Storybook for Next.js with Vite +hideRendererSelector: true +sidebar: + order: 2 + title: Next.js (Vite) +--- + +Storybook for Next.js (Vite) is the **recommended** [framework](../../contribute/framework.mdx) for developing and testing UI components in isolation for [Next.js](https://nextjs.org/) applications. It uses [Vite](https://vitejs.dev/) for faster builds and better performance. It includes: + +* πŸ”€ Routing +* πŸ–Ό Image optimization +* ‡️ Absolute imports +* 🎨 Styling +* ⚑ Vite-powered builds +* πŸ’« and more! + +This Vite-based framework offers several advantages over the Webpack-based [`@storybook/nextjs`](./nextjs.mdx) framework: + +* ⚑ **Faster builds** - Vite's build system is significantly faster than Webpack +* πŸ”§ **Modern tooling** - Uses the latest build tools and optimizations +* πŸ§ͺ **Better test support** - Full support for the [Vitest addon](../../writing-tests/integrations/vitest-addon.mdx) and other testing features +* πŸ“¦ **Simpler configuration** - No need for Babel or complex Webpack configurations +* 🎯 **Better development experience** - Faster HMR (Hot Module Replacement) and dev server startup + +## Requirements + +* Next.js β‰₯ 14.1 + +## Getting started + +### In a project without Storybook + +When you run `storybook init` in your Next.js project, Storybook will automatically detect your project and select the `@storybook/nextjs-vite` framework **unless** your project has custom Webpack or Babel configurations that may be incompatible with Vite. + +Follow the prompts after running this command in your Next.js project's root directory: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +[More on getting started with Storybook.](../install.mdx) + + + +If your project has a custom `webpack.config.js` or `.babelrc` file, `storybook init` will prompt you to choose between: + +- **`@storybook/nextjs-vite`** (recommended) - Faster, more modern, supports latest testing features +- **`@storybook/nextjs`** (Webpack 5) - Better compatibility with custom Webpack/Babel configurations + +Choose `nextjs-vite` if you're willing to migrate your custom configurations to Vite. Choose `nextjs` (Webpack 5) if you need to keep your existing Webpack/Babel setup. + + + +### In a project with Storybook + +This framework is designed to work with Storybook 10+. If you're not already using v10, upgrade with this command: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +#### Automatic migration + +When running the `upgrade` command above, you should get a prompt asking you to migrate to `@storybook/nextjs-vite`, which should handle everything for you. In case that auto-migration does not work for your project, refer to the manual migration below. + +You can also use the [`nextjs-to-nextjs-vite` automigration](#migrating-from-webpack) to migrate from the Webpack-based `@storybook/nextjs` framework to this Vite-based framework. + +#### Manual migration + +First, install the framework: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +Then, update your `.storybook/main.js|ts` to change the framework property: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + + + +If your Storybook configuration contains custom Webpack operations in [`webpackFinal`](../../api/main-config/main-config-webpack-final.mdx), you will likely need to create equivalents in [`viteFinal`](../../api/main-config/main-config-vite-final.mdx). + +For more information, see the [Vite builder documentation](../../builders/vite.mdx#migrating-from-webpack). + + + +Finally, if you were using Storybook plugins to integrate with Next.js, those are no longer necessary when using this framework and can be removed: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +#### Migrating from Webpack + +Storybook provides a migration tool for migrating to this framework from the Webpack-based Next.js framework, `@storybook/nextjs`. To migrate, run this command: + +```bash +npx storybook automigrate nextjs-to-nextjs-vite +``` + +This automigration tool performs the following actions: + +1. Updates `package.json` files to replace `@storybook/nextjs` with `@storybook/nextjs-vite` +2. Updates `.storybook/main.js|ts` to change the framework property +3. Scans and updates import statements in your story files and configuration files + + + +If your project has custom Webpack configurations in `.storybook/main.js|ts` (via `webpackFinal`), you'll need to migrate those to Vite configuration (via `viteFinal`) after running this automigration. See the [Vite builder documentation](../builders/vite.mdx#migrating-from-webpack) for more information. + + + +## Run the Setup Wizard + +If all goes well, you should see a setup wizard that will help you get started with Storybook introducing you to the main concepts and features, including how the UI is organized, how to write your first story, and how to test your components' response to various inputs utilizing [controls](../../essentials/controls.mdx). + +![Storybook onboarding](../../_assets/get-started/example-onboarding-wizard.png) + +If you skipped the wizard, you can always run it again by adding the `?path=/onboarding` query parameter to the URL of your Storybook instance, provided that the example stories are still available. + +## Next.js's Image component + +This framework allows you to use Next.js's [next/image](https://nextjs.org/docs/pages/api-reference/components/image) with no configuration. + +### Local images + +[Local images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#local-images) are supported. + +```jsx title="index.jsx" +import Image from 'next/image'; +import profilePic from '../public/me.png'; + +function Home() { + return ( + <> +

My Homepage

+ Picture of the author +

Welcome to my homepage!

+ + ); +} +``` + +### Remote images + +[Remote images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#remote-images) are also supported. + +```jsx title="index.jsx" +import Image from 'next/image'; + +export default function Home() { + return ( + <> +

My Homepage

+ Picture of the author +

Welcome to my homepage!

+ + ); +} +``` + +## Next.js font optimization + +[next/font](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) is partially supported in Storybook. The packages `next/font/google` and `next/font/local` are supported. + +### `next/font/google` + +You don't have to do anything. `next/font/google` is supported out of the box. + +### `next/font/local` + +For local fonts you have to define the [src](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts) property. +The path is relative to the directory where the font loader function is called. + +If the following component defines your localFont like this: + +```js title="src/components/MyComponent.js" +import localFont from 'next/font/local'; + +const localRubikStorm = localFont({ src: './fonts/RubikStorm-Regular.ttf' }); +``` + +The Vite-based framework automatically handles font path mapping, so you don't need to configure `staticDirs` for fonts like you would with the Webpack-based framework. + +### Not supported features of `next/font` + +The following features are not supported (yet). Support for these features might be planned for the future: + +* [Support font loaders configuration in next.config.js](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts) +* [fallback](https://nextjs.org/docs/pages/api-reference/components/font#fallback) option +* [adjustFontFallback](https://nextjs.org/docs/pages/api-reference/components/font#adjustfontfallback) option +* [preload](https://nextjs.org/docs/pages/api-reference/components/font#preload) option gets ignored. Storybook handles Font loading its own way. +* [display](https://nextjs.org/docs/pages/api-reference/components/font#display) option gets ignored. All fonts are loaded with display set to "block" to make Storybook load the font properly. + +### Mocking fonts during testing + +Occasionally fetching fonts from Google may fail as part of your Storybook build step. It is highly recommended to mock these requests, as those failures can cause your pipeline to fail as well. Next.js [supports mocking fonts](https://github.com/vercel/next.js/blob/725ddc7371f80cca273779d37f961c3e20356f95/packages/font/src/google/fetch-css-from-google-fonts.ts#L36) via a JavaScript module located where the env var `NEXT_FONT_GOOGLE_MOCKED_RESPONSES` references. + +For example, using [GitHub Actions](https://www.chromatic.com/docs/github-actions): + +```yaml title=".github/workflows/ci.yml" +- uses: chromaui/action@latest + env: + #πŸ‘‡ the location of mocked fonts to use + NEXT_FONT_GOOGLE_MOCKED_RESPONSES: ${{ github.workspace }}/mocked-google-fonts.js + with: + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} +``` + +Your mocked fonts will look something like this: + +```js title="mocked-google-fonts.js" +//πŸ‘‡ Mocked responses of google fonts with the URL as the key +module.exports = { + 'https://fonts.googleapis.com/css?family=Inter:wght@400;500;600;800&display=block': ` + /* cyrillic-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiJ-Ek-_EeAmM.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; + } + /* more font declarations go here */ + /* latin */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiJ-Ek-_EeA.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + }`, +}; +``` + +## Next.js routing + +[Next.js's router](https://nextjs.org/docs/pages/building-your-application/routing) is automatically stubbed for you so that when the router is interacted with, all of its interactions are automatically logged to the [Actions panel](../../essentials/actions.mdx). + + + +You should only use `next/router` in the `pages` directory. In the `app` directory, it is necessary to use `next/navigation`. + + + +### Overriding defaults + +Per-story overrides can be done by adding a `nextjs.router` property onto the story [parameters](../../writing-stories/parameters.mdx). The framework will shallowly merge whatever you put here into the router. + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + + + +These overrides can also be applied to [all stories for a component](../../api/parameters.mdx#meta-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply. + + + +### Default router + +The default values on the stubbed router are as follows (see [globals](../../essentials/toolbars-and-globals.mdx#globals) for more details on how globals work). + +```ts +// Default router +const defaultRouter = { + // The locale should be configured globally: https://storybook.js.org/docs/essentials/toolbars-and-globals#globals + locale: globals?.locale, + asPath: '/', + basePath: '/', + isFallback: false, + isLocaleDomain: false, + isReady: true, + isPreview: false, + route: '/', + pathname: '/', + query: {}, +}; +``` + +Additionally, the [`router` object](https://nextjs.org/docs/pages/api-reference/functions/use-router#router-object) contains all of the original methods (such as `push()`, `replace()`, etc.) as mock functions that can be manipulated and asserted on using [regular mock APIs](https://vitest.dev/api/mock.html). + +To override these defaults, you can use [parameters](../../writing-stories/parameters.mdx) and [`beforeEach`](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#setting-up-and-cleaning-up): + +```ts title=".storybook/preview.js|ts" +import type { Preview } from '@storybook/nextjs-vite'; + +// πŸ‘‡ Must include the `.mock` portion of filename to have mocks typed correctly +import { getRouter } from "@storybook/nextjs-vite/router.mock"; + +const preview: Preview = { + parameters: { + nextjs: { + // πŸ‘‡ Override the default router properties + router: { + basePath: '/app/', + }, + }, + }, + async beforeEach() { + // πŸ‘‡ Manipulate the default router method mocks + getRouter().push.mockImplementation(() => { + /* ... */ + }); + }, +}; +``` + +## Next.js navigation + + + +Please note that [`next/navigation`](https://nextjs.org/docs/app/building-your-application/routing) can only be used in components/pages in the `app` directory. + + + +### Set `nextjs.appDirectory` to `true` + +If your story imports components that use `next/navigation`, you need to set the parameter `nextjs.appDirectory` to `true` in for that component's stories: + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +If your Next.js project uses the `app` directory for every page (in other words, it does not have a `pages` directory), you can set the parameter `nextjs.appDirectory` to `true` in the [`.storybook/preview.js|ts`](../../configure/index.mdx#configure-story-rendering) file to apply it to all stories. + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +### Overriding defaults + +Per-story overrides can be done by adding a `nextjs.navigation` property onto the story [parameters](../../writing-stories/parameters.mdx). The framework will shallowly merge whatever you put here into the router. + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + + + +These overrides can also be applied to [all stories for a component](../../api/parameters.mdx#meta-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply. + + + +### `useSelectedLayoutSegment`, `useSelectedLayoutSegments`, and `useParams` hooks + +The `useSelectedLayoutSegment`, `useSelectedLayoutSegments`, and `useParams` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments or the params you want to use. + +{/* prettier-ignore-start */} + + + +With the above configuration, the component rendered in the stories would receive the following values from the hooks: + +```js title="NavigationBasedComponent.js" +import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation'; + +export default function NavigationBasedComponent() { + const segment = useSelectedLayoutSegment(); // dashboard + const segments = useSelectedLayoutSegments(); // ["dashboard", "analytics"] + const params = useParams(); // {} + // ... +} +``` + +{/* prettier-ignore-end */} + +To use `useParams`, you have to use a segments array where each element is an array containing two strings. The first string is the param key and the second string is the param value. + +{/* prettier-ignore-start */} + + + +{/* prettier-ignore-end */} + +With the above configuration, the component rendered in the stories would receive the following values from the hooks: + +```js title="ParamsBasedComponent.js" +import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation'; + +export default function ParamsBasedComponent() { + const segment = useSelectedLayoutSegment(); // hello + const segments = useSelectedLayoutSegments(); // ["hello", "nextjs"] + const params = useParams(); // { slug: "hello", framework: "nextjs" } + ... +} +``` + + + +These overrides can also be applied to [a single story](../../api/parameters.mdx#story-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply. + + + +The default value of `nextjs.navigation.segments` is `[]` if not set. + +### Default navigation context + +The default values on the stubbed navigation context are as follows: + +```ts +// Default navigation context +const defaultNavigationContext = { + pathname: '/', + query: {}, +}; +``` + +Additionally, the [`router` object](https://nextjs.org/docs/app/api-reference/functions/use-router#userouter) contains all of the original methods (such as `push()`, `replace()`, etc.) as mock functions that can be manipulated and asserted on using [regular mock APIs](https://vitest.dev/api/mock.html). + +To override these defaults, you can use [parameters](../../writing-stories/parameters.mdx) and [`beforeEach`](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#setting-up-and-cleaning-up): + +```ts title=".storybook/preview.js|ts" +import type { Preview } from '@storybook/nextjs-vite'; + +// πŸ‘‡ Must include the `.mock` portion of filename to have mocks typed correctly +import { getRouter } from '@storybook/nextjs-vite/navigation.mock'; + +const preview: Preview = { + parameters: { + nextjs: { + // πŸ‘‡ Override the default navigation properties + navigation: { + pathname: '/app/', + }, + }, + }, + async beforeEach() { + // πŸ‘‡ Manipulate the default navigation method mocks + getRouter().push.mockImplementation(() => { + /* ... */ + }); + }, +}; +``` + +## Next.js Head + +[`next/head`](https://nextjs.org/docs/pages/api-reference/components/head) is supported out of the box. You can use it in your stories like you would in your Next.js application. Please keep in mind, that the Head `children` are placed into the head element of the iframe that Storybook uses to render your stories. + +## Sass/Scss + +[Global Sass/Scss stylesheets](https://nextjs.org/docs/pages/building-your-application/styling/sass) are supported without any additional configuration as well. Just import them into [`.storybook/preview.js|ts`](../../configure/index.mdx#configure-story-rendering) + +```js title=".storybook/preview.js|ts" +import '../styles/globals.scss'; +``` + +This will automatically include any of your [custom Sass configurations](https://nextjs.org/docs/pages/building-your-application/styling/sass#customizing-sass-options) in your `next.config.js` file. + +```js title="next.config.js" +import * as path from 'path'; + +export default { + // Any options here are included in Sass compilation for your stories + sassOptions: { + includePaths: [path.join(process.cwd(), 'styles')], + }, +}; +``` + +## CSS/Sass/Scss Modules + +[CSS modules](https://nextjs.org/docs/pages/building-your-application/styling/css-modules) work as expected. + +```jsx title="src/components/Button.jsx" +// This import will work in Storybook +import styles from './Button.module.css'; +// Sass/Scss is also supported +// import styles from './Button.module.scss' +// import styles from './Button.module.sass' + +export function Button() { + return ( + + ); +} +``` + +## PostCSS + +Next.js lets you [customize PostCSS config](https://nextjs.org/docs/pages/building-your-application/configuring/post-css). Thus this framework will automatically handle your PostCSS config for you. + +This allows for cool things like zero-config Tailwind! (See [Next.js' example](https://github.com/vercel/next.js/tree/canary/packages/create-next-app/templates/default-tw)) + +## Absolute imports + +[Absolute imports](https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases#absolute-imports) from the root directory are supported. + +```jsx title="index.jsx|tsx" +// All good! +import Button from 'components/button'; +// Also good! +import styles from 'styles/HomePage.module.css'; + +export default function HomePage() { + return ( + <> +

Hello World

+