资讯动态

Storybook CSF 实战:为 Checkbox 组件编写「Unchecked」状态 Story(CSF 3 / Svelte CSF / CSF Next 全框架对照)

发布时间:2026/9/18 20:55:27 来源:尧图企业网站定制
Storybook CSF 实战为 Checkbox 组件编写「Unchecked」状态 StoryCSF 3 / Svelte CSF / CSF Next 全框架对照本文围绕 Storybook 官方文档代码片段 docs/_snippets/checkbox-story-csf.md 展开。该片段本身并非散文式教程而是一份「可被文档站点多框架切换渲染」的对照式代码示例集它用 16 段代码覆盖 Angular、Svelte、React、Vue、Web Components 等渲染器演示在 Component Story FormatCSF下为一个 Checkbox 组件定义名为Unchecked的默认状态 Story并用args传入label: Unchecked作为组件输入。通过逐段拆解这些示例你将掌握 CSF 3 的对象式 Story、Svelte CSF 的defineMeta/Story写法、Web Components 的标签字符串引用以及实验性 CSF Next 的preview.meta()API并能把这些 Story 无缝嵌入 MDX 组件文档中渲染。该代码片段在文档体系中的位置在 Storybook 仓库中docs/_snippets/目录存放的是所有教程页共用的「可切换代码片段」。它们由文档站点的CodeSnippets组件加载并根据当前阅读者选择的框架、语言与写法选项卡只渲染对应的那一段代码。这一份checkbox-story-csf.md是 MDX 教程页 的主角之一。该页第 15 行起以Checkbox.mdx为例讲解「用 Markdown JSX 写组件文档」第 17 行引用 checkbox-story.md展示 MDX 文件本体第 21 行引用我们讨论的checkbox-story-csf.md并说明它承载的是被 MDX 引用的、以 CSF 编写的Checkbox.stories.js|ts故事文件This MDX file references a story file,Checkbox.stories.js|ts, that is written in Component Story Format (CSF).换句话说CSF 负责定义组件有哪些状态MDX 负责把状态编排成可读的文档。仓库中另一个片段 checkbox-story-grouped.md 展示了同系列示例如何通过title: Design System/Atoms/Checkbox进行分组与层级命名可一并对照阅读。CSF 3用「默认导出 具名导出」描述组件元数据与 StoryCSF 是官方推荐的故事编写格式本质是一个基于 ES6 模块的开放标准详见 docs/api/csf/index.mdx。一个 CSF 故事文件由两部分构成默认导出default export描述组件元数据至少包含component字段Addons 依赖它生成属性表、展示组件元信息可选title、decorators、parameters等具名导出named exports默认情况下每一个具名导出都是一个 Story 对象。以最常见的CSF 3写法为例下面是用 JavaScript 编写的通用版本同一文件既可用于.js也可用于.jsx覆盖 React 等 JSX 生态// Checkbox.stories.js|jsx —— CSF 3common import { Checkbox } from ./Checkbox; export default { component: Checkbox, }; export const Unchecked { args: { label: Unchecked, }, };要点拆解export default { component: Checkbox }声明「本文件围绕 Checkbox 编写」Story 将默认渲染该组件并把args作为输入分发给它export const Unchecked { args: {...} }声明一个名为Unchecked的 Story 对象。与 CSF 2 的函数式Unchecked.bind({})不同CSF 3 中具名导出是对象因此可以放心地用 JS 展开运算符复用其上的所有注解args是 Storybook 6.0 起引入的「具名输入」。组件的外显差异选中/未选中、主按钮/次按钮通常只需不同的args就能表达本例中的label: Unchecked会作为属性传给组件若未显式指定Story 在侧边栏的显示名由具名导出经startCase规则转换而来Unchecked→Unchecked。官方建议具名导出一律使用 UpperCamelCase详见 docs/api/csf/index.mdx 中导出标识符与显示名的映射表。TypeScript 版本satisfiesStoryObj在 TS/TSX 项目中推荐用satisfies让编辑器同时做类型收窄与推断并借助StoryObj获得自动补全// Checkbox.stories.ts|tsx —— CSF 3common // 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 Metatypeof Checkbox; export default meta; type Story StoryObjtypeof meta; export const Unchecked: Story { args: { label: Unchecked, }, };注意此处相对 纯 JS 版 的两个差异import type { Meta, StoryObj } from storybook/your-framework中的包名是占位符实际使用时要替换为storybook/react-vite、storybook/nextjs、storybook/vue3-vite等具体框架包源码片段中以注释形式标注了这一点用const meta {...} satisfies Metatypeof Checkbox约束元数据再以type Story StoryObjtypeof meta让每个具名导出与组件的 props 类型自动对齐——写错属性名会在编译期直接报错。Angular 版本从组件类导入Angular 渲染器同样遵循 CSF 3区别在于组件来源与类型来自storybook/angular// Checkbox.stories.ts —— CSF 3angular import type { Meta, StoryObj } from storybook/angular; import { Checkbox } from ./checkbox.component; const meta: MetaCheckbox { component: Checkbox, }; export default meta; type Story StoryObjCheckbox; export const Unchecked: Story { args: { label: Unchecked, }, };Angular 下Checkbox是从./checkbox.component导入的组件类MetaCheckbox/StoryObjCheckbox直接以组件类型作为泛型参数label会被编译为组件Input()的输入值。Svelte两种写法并存Svelte 是这套示例中唯一提供「两套范式」的渲染器这与仓库教程页 docs/writing-stories/index.mdx 的描述一致可以走标准 CSF默认导出 具名导出也可以使用 Svelte 生态惯用的storybook/addon-svelte-csf。标准 CSF 3JS / TS// Checkbox.stories.js —— CSF 3svelte import Checkbox from ./Checkbox.svelte; export default { component: Checkbox, }; export const Unchecked { args: { label: Unchecked, }, };TypeScript 版则按常见惯例引入框架包占位符storybook/your-framework实际使用时替换为svelte-vite或sveltekit该提示写在片段源码注释中// Checkbox.stories.ts —— CSF 3svelte // Replace your-framework with svelte-vite or sveltekit import type { Meta, StoryObj } from storybook/your-framework; import Checkbox from ./Checkbox.svelte; const meta { component: Checkbox, } satisfies Metatypeof Checkbox; export default meta; type Story StoryObjtypeof meta; export const Unchecked: Story { args: { label: Unchecked, }, };Svelte CSFdefineMetaStory标准 CSF 对 Svelte 社区而言并非唯一选择。官方教程页将其描述为社区驱动的平行方案用defineMeta描述组件用其返回的Story组件定义每个 Story。JS 与 TS 两种语言下的写法几乎一致!-- Checkbox.stories.svelte —— Svelte CSFjs -- script module import { defineMeta } from storybook/addon-svelte-csf; import Checkbox from ./Checkbox.svelte; const { Story } defineMeta({ component: Checkbox, }); /script Story nameUnchecked args{{ label: Unchecked, }} /!-- Checkbox.stories.svelte —— Svelte CSFts -- script module import { defineMeta } from storybook/addon-svelte-csf; import Checkbox from ./Checkbox.svelte; const { Story } defineMeta({ component: Checkbox, }); /script Story nameUnchecked args{{ label: Unchecked, }} /Svelte CSF 的关键差异在于「命名方式」Story 的显示名不再由导出标识符推断而是通过Story组件的name属性显式声明侧边栏直接显示name的值。args、decorators、parameters等注解同样以属性形式写在Story上详见 docs/api/csf/index.mdx 中针对 Svelte 渲染器的说明。还有一个易踩的坑记录在 docs/writing-stories/index.mdx 中Svelte CSF 下不能用args传children需要在Story开闭标签之间书写子内容它会作为 Svelte 的childrensnippet prop 传入。Web Components直接用自定义元素标签名Web Components 渲染器下component字段不再引用框架组件类/对象而是注册后的自定义元素标签字符串此处为demo-checkboxStorybook 会据此实例化对应 Custom Element// Checkbox.stories.js —— CSF 3web-components export default { component: demo-checkbox, }; export const Unchecked { args: { label: Unchecked, }, };TypeScript 版本从storybook/web-components-vite导入类型。由于没有可推导 props 的组件对象Meta与StoryObj均为无泛型/宽泛形式// Checkbox.stories.ts —— CSF 3web-components import type { Meta, StoryObj } from storybook/web-components-vite; const meta: Meta { component: demo-checkbox, }; export default meta; type Story StoryObj; export const Unchecked: Story { args: { label: Unchecked, }, };与 React/Vue 等版本不同Web Components 版不需要 import 组件文件——前提是标签已在项目中注册例如由当前文档的组件库或 preview 的全局配置完成注册。CSF Next实验性 preview.meta()与meta.story()代码片段中与CSF 3并列的选项卡CSF Next 展示了一套仍在实验期的 API形态上是一套「无默认导出」的函数式写法。其固定套路是从项目的.storybook/preview即 preview 配置文件导出导入默认的preview调用preview.meta({ component, ... })得到meta调用meta.story({ args, ... })声明 Story并直接具名导出。Angular、Web Components、React、Vue 四种渲染器都给出了对应变体结构完全平行// Checkbox.stories.ts —— CSF Nextangular import preview from ../.storybook/preview; import { Checkbox } from ./checkbox.component; const meta preview.meta({ component: Checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });// Checkbox.stories.js —— CSF Nextweb-components import preview from ../.storybook/preview; const meta preview.meta({ component: demo-checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });// Checkbox.stories.ts —— CSF Nextweb-components import preview from ../.storybook/preview; const meta preview.meta({ component: demo-checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });// Checkbox.stories.ts|tsx —— CSF Nextreact import preview from ../.storybook/preview; import { Checkbox } from ./Checkbox; const meta preview.meta({ component: Checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });// Checkbox.stories.js|jsx —— CSF Nextreact import preview from ../.storybook/preview; import { Checkbox } from ./Checkbox; const meta preview.meta({ component: Checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });// Checkbox.stories.ts —— CSF Nextvue import preview from ../.storybook/preview; import Checkbox from ./Checkbox.vue; const meta preview.meta({ component: Checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });// Checkbox.stories.js —— CSF Nextvue import preview from ../.storybook/preview; import Checkbox from ./Checkbox.vue; const meta preview.meta({ component: Checkbox, }); export const Unchecked meta.story({ args: { label: Unchecked, }, });可见 CSF Next 的两处统一其一../.storybook/preview是相对于故事文件位置的导入路径你的项目需把该路径调整为真实相对路径其二Angular 从./checkbox.component导组件类、React 从./Checkbox具名导入、Vue 从./Checkbox.vue默认导入——变化的只有组件来源API 骨架完全一致。片段中还保留了一段注释!-- JS snippets still needed while providing both CSF 3 Next --说明文档站点在同时提供 CSF 3 与 CSF Next 两种选项卡时仍需为每个语言JS/TS分别维护片段——这也是本代码片段存在大量平行变体的直接原因。组件的 story 定义与 CSF 3 中 Args 的作用无论采用上面哪种范式Unchecked这个 Story 的语义核心都在于args: { label: Unchecked }。按 docs/api/csf/index.mdx 的说明Args 自 SB 6.0 起成为 Story 的标准输入可被 addons 动态更新Controls、Actions等 addon 可以在界面上直接修改 args让 Story 在渲染期间实时改变这是文档里也能交互的基础比硬编码渲染更可移植写法本身不依赖某个具体 addon 或框架渲染器故事文件可以跨工具复用无需自定义 render如果 Story 只是「把 args 展开进组件」本例即如此CSF 3 会使用各渲染器内置的默认渲染函数Unchecked里无需再写任何render。Story 命名与显示的换算规则若未在 Story 对象上显式提供name显示名按storyNameFromExport LodashstartCase规则转换docs/api/csf/index.mdx 有完整映射表。Unchecked这类 UpperCamelCase 单词会被原样展示而some_custom_NAME这类命名则会被拆分为多词。需要特殊字符、保留字或稳定 Story ID 时才建议改用name字段Svelte CSF 的Story name即属此类。把 Unchecked Story 渲染进 MDX 组件文档定义好Checkbox.stories.*后接下来就是 docs/writing-docs/mdx.mdx 中Checkbox.mdx的编排逻辑。先通过import * as CheckboxStories from ./Checkbox.stories把整个故事文件的导出命名空间引入然后用两个 Doc Block 完成两件事完整片段见 checkbox-story.mdMeta 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} /Meta of{CheckboxStories} /把文档页挂到 Checkbox 故事的相邻层级sidebar 默认节点名为Docs可通过name或title属性自定义。MDX 教程页特别提醒of应引用故事文件的完整导出集合CheckboxStories而不是组件本身否则可能引发文档渲染问题Canvas of{CheckboxStories.Unchecked} /把Unchecked这个 Story 以内联 Canvas 形式嵌入正文——上文任何一种 CSF 变体产出的具名 Story 都能在此处被引用MDX 文档运行在 React 运行时中而其中的 Story 仍按其自身渲染器React/Vue/Angular/Svelte/Web Components 等运行这正是 CSF 故事文件能做到一次定义、文档与组件生态互通的原因。如何选择范式使用场景推荐范式依据React / Vue / Angular / 通用 TS 项目CSF 3 对象式 satisfies官方推荐、类型安全、可展开复用Svelte 项目Svelte CSFdefineMeta/Story或标准 CSF 3docs/writing-stories/index.mdx 同时介绍两种Web ComponentsCSF 3component传自定义元素标签名无需导入组件模块尝鲜新 API、消除默认导出CSF Nextpreview.meta()/meta.story()片段中以 实验标记同一份 Checkbox 故事文件之所以在 MDX 教程 中能以十余种形态呈现正是得益于 CSF 的跨框架可移植性掌握Unchecked这一个例子也就掌握了在任何受支持渲染器中声明组件默认状态的标准套路。如需继续深入可阅读 CSF 规范详解含从 CSF 2 升级到 CSF 3 的 codemod 指引、书写 Story 总览以及 命名与层级组织 中配套的checkbox-story-grouped分组示例。创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价