Docs
Storybook Docs

侧边栏和 URL

Watch a video tutorial

Storybook 的侧边栏列出了按组件分组的所有故事。当你有许多组件时,你可能还希望对这些组件进行分组。为此,你可以将 / 分隔符添加到 CSF 文件的 title,Storybook 将根据通用前缀将故事分组:

¥Storybook’s sidebar lists all your stories grouped by component. When you have many components, you may also wish to group those components. To do so, you can add the / separator to the title of your CSF file, and Storybook will group the stories into groups based on common prefixes:

Storybook sidebar anatomy

我们建议使用镜像组件文件系统路径的嵌套方案。例如,如果你有一个文件 components/modals/Alert.js,请将 CSF 文件命名为 components/modals/Alert.stories.js 并将其命名为 Components/Modals/Alert

¥We recommend using a nesting scheme that mirrors the filesystem path of the components. For example, if you have a file components/modals/Alert.js, name the CSF file components/modals/Alert.stories.js and title it Components/Modals/Alert.

¥Roots

默认情况下,Storybook 会将你的顶层节点视为“根”。根在 UI 中显示为层次结构的“部分”。更底层的组将显示为文件夹:

¥By default, Storybook will treat your top-level nodes as “roots”. Roots are displayed in the UI as “sections” of the hierarchy. Lower level groups will show up as folders:

Storybook sidebar story roots

如果你希望将顶层节点显示为文件夹而不是根,则可以在 ./storybook/manager.js 中将 sidebar.showRoots 选项设置为 false

¥If you’d prefer to show top-level nodes as folders rather than roots, you can set the sidebar.showRoots option to false in ./storybook/manager.js:

./storybook/manager.js
import { addons } from '@storybook/manager-api';
 
addons.setConfig({
  sidebar: {
    showRoots: false,
  },
});

故事的永久链接

¥Permalink to stories

默认情况下,Storybook 根据组件标题和故事名称为每个故事生成一个 id。此 id 特别用于每个故事的 URL,并且该 URL 可以用作永久链接(主要是当你 publish Storybook 时)。

¥By default, Storybook generates an id for each story based on the component title and the story name. This id in particular is used in the URL for each story, and that URL can serve as a permalink (primarily when you publish your Storybook).

考虑以下故事:

¥Consider the following story:

FooBar.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Foo } from './Foo';
 
const meta: Meta<typeof Foo> = {
  /* 👇 The title prop is optional.
   * See https://storybook.js.org/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Foo/Bar',
  component: Foo,
};
 
export default meta;
type Story = StoryObj<typeof Foo>;
 
export const Baz: Story = {};

Storybook 的 ID 生成逻辑将为其提供 id foo-bar--baz,因此链接将是 ?path=/story/foo-bar--baz

¥Storybook's ID-generation logic will give this the id foo-bar--baz, so the link would be ?path=/story/foo-bar--baz.

可以手动设置故事的 ID,如果你想在不破坏永久链接的情况下重命名故事,这将很有帮助。假设你想将层次结构中的位置更改为 OtherFoo/Bar,将故事名称更改为 Moo。以下是如何执行此操作:

¥It is possible to manually set the story's id, which is helpful if you want to rename stories without breaking permalinks. Suppose you want to change the position in the hierarchy to OtherFoo/Bar and the story name to Moo. Here's how to do that:

FooBar.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Foo } from './Foo';
 
const meta: Meta<typeof Foo> = {
  /* 👇 The title prop is optional.
   * See https://storybook.js.org/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'OtherFoo/Bar',
  component: Foo,
  id: 'Foo/Bar', // Or 'foo-bar' if you prefer
};
 
export default meta;
type Story = StoryObj<typeof Foo>;
 
export const Baz: Story = {
  name: 'Insert name here',
};

Storybook 将优先考虑 id 而不是标题来生成 ID(如果提供),并优先考虑 story.name 而不是导出密钥来显示。

¥Storybook will prioritize the id over the title for ID generation if provided and prioritize the story.name over the export key for display.

CSF 3.0 自动标题

¥CSF 3.0 auto-titles

Storybook 6.4 引入了 CSF 3.0 作为一项实验性功能,可让你更紧凑地编写故事。假设你已经在使用这种格式来编写故事。在这种情况下,你可以从默认导出中省略 title 元素,并允许 Storybook 根据文件的物理位置自动推断它。例如,给定以下配置和故事:

¥Storybook 6.4 introduced CSF 3.0 as an experimental feature, allowing you to write stories more compactly. Suppose you're already using this format to write your stories. In that case, you can omit the title element from the default export and allow Storybook automatically infer it based on the file's physical location. For example, given the following configuration and story:

.storybook/main.ts
// Replace your-framework with the framework you are using (e.g., react-webpack5, vue3-vite)
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  framework: '@storybook/your-framework',
  stories: ['../src'],
};
 
export default config;

当 Storybook 加载时,故事可以作为 components/My Component 显示在侧边栏中。

¥When Storybook loads, the story can show up in the sidebar as components/My Component.

自动标题与明确的标题选项一起使用,例如组件的 title 和故事的 name

¥Auto-titles work with explicit titling options like the component's title and the story's name:

src/components/Button/Button.stories.tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<Button> = {
  // Sets the name for the stories container
  title: 'components/Button',
  // The component name will be used if `title` is not set
  component: Button,
};
 
export default meta;
type Story = StoryObj<typeof Button>;
 
// The story variable name will be used if `name` is not set
const Primary: Story = {
  // Sets the name for that particular story
  name: 'Primary',
  args: {
    label: 'Button',
  },
};

自动标题文件名大小写

¥Auto-title filename case

从 Storybook 6.5 开始,自动生成的故事标题不再依赖 Lodash 的 startCase。相反,文件名大小写被保留,允许对故事标题进行额外的控制。例如,components/My Component 将被定义为 components/MyComponent

¥Starting with Storybook 6.5, story titles generated automatically no longer rely on Lodash's startCase. Instead, the file name casing is preserved, allowing additional control over the story title. For example, components/My Component will be defined as components/MyComponent.

如果需要,你可以通过添加以下配置恢复到以前的模式:

¥If you need, you can revert to the previous pattern by adding the following configuration:

.storybook/manager.js
import { addons } from '@storybook/manager-api';
 
import startCase from 'lodash/startCase.js';
 
addons.setConfig({
  sidebar: {
    renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)),
  },
});

自动标题冗余文件名

¥Auto-title redundant filenames

除了改进故事文件名大小写之外,还引入了一种新的启发式方法,如果文件名与目录名同名,或者名为 index.stories.js|ts,则删除冗余名称。例如,在侧边栏中将 components/MyComponent/MyComponent.stories.js 定义为 Components/MyComponent/MyComponent 之前。现在它将被定义为 Components/MyComponent

¥In addition to improvements to the story file name casing, a new heuristic was introduced, removing redundant names in case the filename has the same name as the directory name, or if it's called index.stories.js|ts. For example, before components/MyComponent/MyComponent.stories.js was defined as Components/MyComponent/MyComponent in the sidebar. Now it will be defined as Components/MyComponent.

如果你需要保留命名方案,你可以将 title 元素添加到默认导出。例如:

¥If you need to preserve the naming scheme, you can add the title element to the default export. For example:

components/MyComponent/MyComponent.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { MyComponent } from './MyComponent';
 
const meta: Meta<typeof MyComponent> = {
  /* 👇 The title prop is optional.
   * See https://storybook.js.org/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  component: MyComponent,
  title: 'components/MyComponent/MyComponent',
};
 
export default meta;
type Story = StoryObj<typeof MyComponent>;
 
export const Default: Story = {
  args: {
    something: 'Something else',
  },
};

自动标题前缀

¥Auto-title prefixes

此外,如果你自定义 Storybook 以基于 配置对象(包括 titlePrefix)加载故事,Storybook 会自动将所有标题添加到匹配的故事的前缀。例如,假设你有以下配置:

¥Additionally, if you customize your Storybook to load your stories based on a configuration object, including a titlePrefix, Storybook automatically prefixes all titles to matching stories. For example, assuming you have the following configuration:

.storybook/main.ts
// Replace your-framework with the framework you are using (e.g., react-webpack5, vue3-vite)
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  framework: '@storybook/your-framework',
  stories: [
    {
      directory: '../src',
      titlePrefix: 'Custom', // 👈 Configure the title prefix
    },
  ],
};
 
export default config;

当 Storybook 为所有匹配的故事生成标题时,它们将保留 Custom 前缀。

¥When Storybook generates the titles for all matching stories, they'll retain the Custom prefix.

故事索引器

¥Story Indexers

故事索引器 是 Storybook 使用的一组启发式方法,用于根据给定的 glob 模式抓取文件系统以搜索匹配的故事,然后用于生成 index.json(以前称为 stories.json)文件,负责用必要的信息填充侧边栏。默认情况下,此启发式方法将查找包含以下方案 *.stories.@(js|jsx|mjs|ts|tsx) 的文件。

¥Story Indexers are a set of heuristics used by Storybook to crawl your filesystem based on a given glob pattern searching for matching stories, which is then used to generate an index.json (formerly stories.json) file responsible for populating the sidebar with the necessary information. By default, this heuristic will look for files that contain the following scheme *.stories.@(js|jsx|mjs|ts|tsx).

你可以提供自己的索引器以包含具有不同命名约定的故事,调整前缀之外的自动标题生成以及许多其他用例。有关更多信息,请参阅 Story Indexers API 参考

¥You can provide your own indexer to include stories with a different naming convention, adjust the automatic title generation beyond a prefix, and many other use cases. For more information, see the Story Indexers API reference.