加入在线直播:周四,美国东部时间上午 11 点,Storybook 9 发布及 AMA 问答
文档
Storybook 文档

MDX

MDX 文件结合了 Markdown 和 Javascript/JSX,用于创建丰富的交互式文档。您可以在文档中使用 Markdown 的可读语法(例如 # heading),包含在 组件 Story 格式 (CSF) 中定义的 Stories,并随时在文件中自由嵌入 JSX 组件块。所有这些都可以同时进行。

此外,您还可以使用 MDX 编写纯文档页面,并将其与 Stories 一起添加到 Storybook 中。

MDX simple example result

基本示例

我们先来看一个例子,Checkbox.mdx,它结合了 Markdown 和一个单独的 Story。

Checkbox.mdx
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
 
import * as CheckboxStories from './Checkbox.stories';
 
<Meta of={CheckboxStories} />
 
# Checkbox
 
A checkbox is a square box that can be activated or deactivated when ticked.
 
Use checkboxes to select one or more options from a list of choices.
 
<Canvas of={CheckboxStories.Unchecked} />

这个 MDX 文件引用了一个 Story 文件 Checkbox.stories.js|ts,该文件使用 组件 Story 格式 (CSF) 编写。

Checkbox.stories.ts|tsx
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Checkbox } from './Checkbox';
 
const meta = {
  component: Checkbox,
} satisfies Meta<typeof Checkbox>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
export const Unchecked: Story = {
  args: {
    label: 'Unchecked',
  },
};

下面是它在 Storybook 中的渲染效果

MDX simple example result

这里有很多内容。我们正在编写 Markdown,编写 JSX,并且还在定义和引用与整个 Storybook 生态系统完全兼容的 Storybook Stories。

让我们分解一下。

MDX 和 CSF

您会注意到的第一件事是,组件文档被划分为不同的格式:一种用于编写描述每个可能组件状态的 Story,另一种用于记录如何使用它们。这种划分利用了每种格式的最佳特性。

  • CSF 非常适合简洁地定义 Stories(组件示例)。如果您使用 TypeScript,它还提供类型安全和自动完成。
  • MDX 非常适合编写结构化文档,并与交互式 JSX 元素结合使用。

MDX 的结构

假设您已经熟悉使用 CSF 编写 Stories,我们可以更详细地剖析 MDX 的各个方面。

文档由多个由空行分隔的块组成。由于 MDX 混合了多种不同的语言,它使用这些空行来区分一个块的开始和下一个块的开始。未能用空白分隔块可能会导致(有时令人费解的)解析错误。

按顺序查看代码块

{ /* Checkbox.mdx */ }

MDX 中的注释是包含 JS 注释的 JSX 块。

Checkbox.mdx
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
 
import * as CheckboxStories from './Checkbox.stories';

导入文件中其余 JSX 中将使用的组件和 Stories。

Checkbox.mdx
import { Meta } from '@storybook/addon-docs/blocks';
 
import * as CheckboxStories from './Checkbox.stories';
 
<Meta of={CheckboxStories} />

Meta 块提供 of 属性时,请确保您引用的是 Story 文件的 默认导出,而不是组件本身,以防止生成的文档出现渲染问题。

Meta 块定义了文档在侧边栏中的位置。在本例中,它位于 Checkbox 的 Stories 旁边。默认情况下,文档侧边栏节点标题为 "Docs",但可以通过传递 name 属性进行自定义(例如,<Meta of={CheckboxStories} name="Info" />)。如果您想在导航层次结构的任意位置放置文档节点,可以使用 title 属性(例如,<Meta title="path/to/node" />)。

# Checkbox
 
A checkbox is a square box that can be activated or deactivated when ticked.
 
Use checkboxes to select one or more options from a list of choices.

MDX 默认支持标准 markdown("commonmark"),并且可以扩展以支持 GitHub Flavored Markdown (GFM) 和其他扩展(参见故障排除 部分了解一些当前限制)。

Checkbox.mdx
import { Canvas } from '@storybook/addon-docs/blocks';
 
import * as CheckboxStories from './Checkbox.stories';
 
<Canvas of={CheckboxStories.Unchecked} />

最后,MDX 支持任意 JSX 块。

在这种情况下,我们利用了“Doc Blocks”,这是一个文档组件库,旨在与 Storybook Stories 配合使用,在文档中显示您的 Stories、组件 API 及与组件交互的 Controls,以及其他实用工具。

除了 Doc Blocks,MDX 还可以包含任意 React 组件,这使其成为一个非常灵活的文档系统。假设您想要为组件创建一个风格化的“应该做和不应该做”列表;您可以使用现成的组件或自己编写。

Guideline.mdx
<Guidelines>
  <Dos>
    - Use buttons for the main actions on your page
    - Identify the primary action and make it `primary`
  </Dos>
  <Donts>
    - Use a button when a link will do (e.g., for navigation-only actions)
    - Use multiple `primary` buttons in a single UI state
  </Donts>
</Guidelines>

已知限制

虽然 MDX 支持多种运行时(ReactPreactVue),但 Storybook 的实现仅支持 React。这意味着您的文档在 React 中渲染,而您的 Stories 在您选择的运行时中渲染(React、Vue、Angular、Web Components、Svelte 等)。

设置自定义文档

除了使用 MDX 为组件编写文档外,您还可以扩展它来编写其他类型的内容,例如组件使用指南或最佳实践。要使用这种格式为您的 Stories 启用自定义文档,请先更新 Storybook 配置文件(即 .storybook/main.js|ts|cjs)。

.storybook/main.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
  framework: '@storybook/your-framework',
  stories: [
    //👇 Your documentation written in MDX along with your stories goes here
    '../src/**/*.mdx',
    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
  ],
  addons: ['@storybook/addon-docs'],
};
 
export default config;

创建一个 MDX 文件来添加您的自定义文档。根据您希望文档在 UI 中如何渲染,您需要考虑以下用例。

使用 Meta Doc Block

如果您需要将组件文档与现有的 Story 匹配,您可以配置 Meta Doc Block 来控制文档的渲染方式。开箱即用,它允许您定义自定义标题或引用需要记录的 Story(即通过 of 属性)。例如:

Button.mdx
import { Meta, Controls } from '@storybook/addon-docs/blocks';
 
<Meta title="Button" />
 
# Definition
 
Button is a clickable interactive element that triggers a response.
 
You can place text and icons inside of a button.
 
Buttons are often used for form submissions and to toggle elements into view.
 
## Usage
 
The component comes in different variants such as `primary`, `secondary`, `large` and `small` which you can use to alter the look and feel of the button.
 
## Inputs
 
Button has the following properties:
 
<Controls />

编写非关联文档

假设您正在为一个现有组件编写文档,并且只提供了 Meta Doc Block,没有附加属性或其他块。在这种情况下,Storybook 会将其视为“非关联”文档,换句话说,一个“仅文档”页面,并且它在侧边栏导航菜单中的渲染方式会不同。

ExampleDocumentation.mdx
import { Meta } from '@storybook/addon-docs/blocks';
 
import * as ExampleComponentStories from './ExampleComponent.stories';
 
{/* 👇 Documentation-only page */}
 
<Meta title="Documentation" />
 
{/* 👇 Component documentation page */}
 
<Meta of={ExampleComponentStories} />

MDX docs only story

使用文件系统

然而,对于某些用例,例如独立页面或甚至作为测试组件的指南,可能不需要提供 Meta Doc Block。在这种情况下,您可以安全地省略它。Storybook 将转而依赖文件的物理位置将文档放置在侧边栏中,用您自己的文档覆盖任何预先存在的自动生成 的文档。例如:

src/components/Select.mdx
# Select
 
Select is a type of input that allows users to choose one or more options from a list of choices.
 
The options are hidden by default and revealed when a user interacts with an element.
 
It shows the currently selected option in its default collapsed state.
 
## Design implementation
 
To help users get acquainted with the existing UI elements, it is recommended to use check the Figma file to see how the select input is implemented.
 
### When to use?
 
In a select input where there are less than 3-4 items, consider using radio boxes, or radio inputs instead.
 
### How to use?
 
To help users understand the options available in a select input, include a default option that is unselectable and acts as a label.

如果您正在覆盖通过 tags 配置属性启用的现有自动生成文档页面,我们建议将其删除以避免错误。

一旦加载自定义 MDX 文档,Storybook 将使用相同的启发式规则推断标题和位置,就像生成 自动标题 Stories 一样,并在侧边栏中将其渲染为 Docs 条目。

使用独立文档页面

编写独立文档页面是一个常见的用例,不仅适用于每个组件,也适用于每个项目。例如,您可能希望记录项目的入门流程及使用说明。为此,您可以创建一个新的 MDX 文件,其中包含结构和内容类似的文档。

src/GettingStarted.mdx
# Getting Started
 
Welcome! Whether you're a designer or a developer, this guide will help you get started and connect you to the essential resources you need.
 
## Table of Contents
 
- [Design Resources](#design-resources)
 
  - [Figma](#figma)
  - [UI/UX Design Guidelines](#uiux-design-guidelines)
  - [Design Assets](#design-assets)
 
- [Development Resources](#development-resources)
  - [Coding Standards](#coding-standards)
  - [Version Control](#version-control)
  - [Development Tools](#development-tools)
 
---
 
## Design Resources
 
### Figma
 
[Figma](https://www.figma.com/) is a collaborative design and prototyping tool. It's the heart of the design process, allowing designers to work together seamlessly.
 
- **Get Access**: If you're not already part of the Figma project, request access from the project lead or manager.
 
### UI/UX Design Guidelines
 
Before you dive into designing, familiarize yourself with our UI/UX design guidelines. They provide valuable insights into our design philosophy and standards.
 
- [UI/UX Guidelines Document](https://your-design-guidelines-link.com)
 
### Design Assets
 
All the essential design assets like logos, icons, and brand guidelines can be found in the Figma project. Ensure you have access and familiarize yourself with these assets for consistency.
 
---
 
## Development Resources
 
### Coding Standards
 
Maintaining a consistent code style is essential for collaborative development. Our coding standards document will guide you on best practices.
 
- [Coding Standards Document](https://your-coding-standards-link.com)
 
### Version Control
 
We use Git for version control. Make sure you have Git installed and are familiar with its basics.
 
### Development Tools
 
Your development environment is critical. Here are some tools and resources to help you set up your workspace:
 
- **Code Editor**: We recommend using [Visual Studio Code](https://vscode.js.cn/) for development. It's highly customizable and supports a wide range of extensions.
 
- **Package Manager**: [npm](https://npmjs.net.cn/) is the package manager we use for JavaScript projects. Install it to manage project dependencies.
 
---

MDX guidelines page

当 Storybook 加载文档时,它将使用文件的物理位置推断页面在侧边栏导航菜单中的位置,并在侧边栏中将其渲染为 Docs 条目。

完全控制自定义文档

将文档应用于每个项目组件时,维护和更新成本可能很高。为了简化此过程,Storybook 提供了一组有用的 UI 组件(即 Doc Blocks),以帮助处理更高级的情况。如果您需要额外的内容,可以使用它们来创建自定义文档。

Button.mdx
import { Meta, Story } from '@storybook/addon-docs/blocks';
 
import * as ButtonStories from './Button.stories';
 
<Meta of={ButtonStories} />
 
# Button
 
Button is a clickable interactive element that triggers a response.
 
You can place text and icons inside of a button.
 
Buttons are often used for form submissions and to toggle elements into view.
 
## Usage
 
<Story of={ButtonStories.Basic} />

使用多个组件

如果您需要在单个文档页面中记录多个组件,可以直接在 MDX 文件中引用它们。在内部,Storybook 会查找 Story 元数据,并将其与您现有的文档组合在一起。例如:

Page.mdx
import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';
 
import * as ListStories from './List.stories';
 
import * as ListItemStories from './ListItem.stories';
 
import * as PageStories from './Page.stories';
 
<Meta of={PageStories} />
 
# Page
 
Page is a layout container that is used to position children in predetermined areas.
 
It's often used to apply consistent positioning for content across pages in an application
 
## Usage
 
<Canvas of={PageStories.Basic} />
 
# List
 
List is a grouping of related items. List can be ordered with multiple levels of nesting.
 
## Usage
 
<Story of={ListStories.Filled} />
 
# List Item
 
List items are used to group related content in a list. They must be nested within a List component.
 
## Usage
 
<Story of={ListItemStories.Starter} meta={ListItemStories} />

从 Markdown 生成文档

如果您需要使用 Markdown 编写的额外内容来扩展文档,可以使用 Markdown Doc Block 导入可用内容,Storybook 将其与您现有的文档一起渲染。例如,如果您有一个 CHANGELOG.md 文件,可以按如下方式导入并渲染到文档页面中:

Changelog.mdx
import { Meta, Markdown } from '@storybook/addon-docs/blocks';
 
import Readme from '../../Changelog.md?raw';
 
<Meta title="Changelog" />
 
# Changelog
 
<Markdown>{Readme}</Markdown>

Markdown Doc Block 提供了额外的配置选项来自定义文档的渲染。有关更多信息,请参阅API 文档

Changelog markdown in an MDX story

另一种改进文档的方法是链接到其他 Stories 和页面。假设您已经有一个具有唯一标识符 some--id 的组件 Story,并且您想将其链接到您的文档页面。在这种情况下,您可以使用 path 查询字符串重定向到与该 Story 相关的文档条目。

[Go to specific documentation page](?path=/docs/some--id)

或者,如果您需要定位到特定的文档部分,可以调整链接指向它。例如:

[Go to the conclusion of the documentation page](?path=/docs/some--id#conclusion)

然而,交叉链接文档不仅限于文档页面。如果您需要引用特定的 Story,可以调整 path 查询并提供该 Story 的唯一标识符。例如:

[Go to specific story canvas](?path=/story/some--id)

通过将此模式与 Controls 插件一起使用,Storybook 根据其处理 URL 以跟踪 args 值的方式,将忽略 Canvas 中的所有锚点。

故障排除

Markdown 表格未正确渲染

如果您正在扩展文档以包含特定功能(例如表格、脚注),使用 Storybook 支持的当前 MDX 版本可能会遇到一些渲染问题。我们建议在配置文件(即 .storybook/main.js|ts)中启用 remark-gfm 插件以正确渲染它们。

.storybook/main.ts
import remarkGfm from 'remark-gfm';
 
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  framework: '@storybook/your-framework',
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    // Other addons go here
    {
      name: '@storybook/addon-docs',
      options: {
        mdxPluginOptions: {
          mdxCompileOptions: {
            remarkPlugins: [remarkGfm],
          },
        },
      },
    },
  ],
};
 
export default config;

remark-gfm 包默认不包含在 Storybook 中,必须作为开发依赖单独安装。要了解如何使用它以及 MDX 引入的其他重大更改,请参阅 GFM 指南 和 MDX 团队提供的 迁移指南,以获取更多信息。

MDX 文档在我的环境中无法渲染

由于 Storybook 依赖 MDX 3 来渲染文档,某些技术限制可能会阻止您迁移到此版本。如果是这种情况,我们准备了一套说明来帮助您过渡到这个新版本。

Storybook 未为我的组件 Stories 创建文档

如果您遇到 Storybook 无法检测和渲染组件 Stories 文档的情况,这可能是由于 Storybook 配置错误造成的。检查您的配置文件(即 .storybook/main.js|ts),并确保 stories 配置元素提供了 Stories 位置的正确路径(例如 ../src/**/*.stories.@(js|jsx|mjs|ts|tsx))。

迁移不稳定并持续失败

默认情况下,运行迁移 命令将提示您根据 Storybook 支持的 MDX 版本更新项目中的现有 MDX 文件。然而,这可能是一个具有破坏性的过程,特别是如果您从使用旧版 MDX 格式的先前 Storybook 版本升级。为了帮助您解决这些问题,我们准备了一些可能对您有帮助的建议。

首先在项目目录中运行以下命令

npx @hipster/mdx2-issue-checker

根据文件数量,您可能需要多次运行该命令才能解决所有问题。

完成后,它将输出导致问题的文件的列表。然后您可以使用此信息手动修复问题。

此外,如果您使用 VSCode,可以添加 MDX 扩展 并启用 MDX 实验性支持,通过将以下内容添加到您的用户设置中,获得 linting、类型检查和自动完成功能

{
  "mdx.server.enable": true
}

如果您仍然遇到问题,建议通过默认的交流渠道(例如 GitHub discussions)向社区寻求帮助。

MDX 文档页面中的 Controls 未更新 Story

如果您通过 inline 配置选项关闭了 Stories 的内联渲染,您将遇到相关 Controls 未更新文档页面中 Story 的情况。这是当前实现的一个已知限制,将在未来的版本中解决。

使用的 React 版本与预期不符

对于大多数项目,Storybook 的 addon-docs 使用项目依赖项中列出的 React 版本。如果未找到,则使用 React 18.2.0。有两个例外情况:

  • Preact 项目将始终使用 React 17
  • Next.js 项目将始终使用随安装的 Next.js 版本附带的 canary 版本,无论项目依赖项中列出的是哪个 React 版本。

如果您在使用 React 版本时遇到问题,可能需要重新创建项目的 node_modules 文件夹,以确保使用了正确的版本。

了解更多 Storybook 文档