story-naming

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Story Naming Conventions

Storybook 故事命名规范

Name Storybook stories to describe what the user sees or does, not how the story works internally.
为Storybook故事命名时,应描述用户所见或操作的内容,而非故事的内部工作原理。

Quick Decision Guide

快速决策指南

Before naming a story, ask:
  1. Does this describe what the user sees or does?
  2. Would a non-technical stakeholder understand this name?
  3. Is this name still accurate without the
    play
    function?
If yes to all three, it's a good name.
为故事命名前,先问自己三个问题:
  1. 这个名称是否描述了用户所见或操作的内容?
  2. 非技术相关的利益相关者能否理解这个名称?
  3. 即使移除
    play
    函数,这个名称是否依然准确?
如果三个问题的答案都是肯定的,那这就是一个好的名称。

Naming Rules

命名规则

Describe User Scenarios or Component States

描述用户场景或组件状态

tsx
// User scenarios (typically with play functions)
export const SelectAndApply: Story = {};
export const SearchByKeyword: Story = {};
export const ClearAllSelections: Story = {};

// Component states (typically static/visual)
export const DisabledState: Story = {};
export const WithPreselectedItems: Story = {};
export const EmptyState: Story = {};
tsx
// User scenarios (typically with play functions)
export const SelectAndApply: Story = {};
export const SearchByKeyword: Story = {};
export const ClearAllSelections: Story = {};

// Component states (typically static/visual)
export const DisabledState: Story = {};
export const WithPreselectedItems: Story = {};
export const EmptyState: Story = {};

Never Expose Implementation Details

切勿暴露实现细节

tsx
// Bad - exposes implementation
export const InteractiveDefault: Story = {};
export const InteractiveWithValidation: Story = {};
export const TestSearchFunctionality: Story = {};
export const PlayFunctionForSearch: Story = {};

// Good - describes user scenario
export const Default: Story = {};
export const WithValidation: Story = {};
export const SearchByKeyword: Story = {};
export const SearchAndFilter: Story = {};
Rationale: The presence of a
play
function already indicates interactivity. Story names should remain accurate even if the
play
function is removed.
tsx
// Bad - exposes implementation
export const InteractiveDefault: Story = {};
export const InteractiveWithValidation: Story = {};
export const TestSearchFunctionality: Story = {};
export const PlayFunctionForSearch: Story = {};

// Good - describes user scenario
export const Default: Story = {};
export const WithValidation: Story = {};
export const SearchByKeyword: Story = {};
export const SearchAndFilter: Story = {};
理由:
play
函数的存在已经表明了交互性。即使移除
play
函数,故事名称也应保持准确。

Story Title Organization

故事标题组织

Use hierarchical
title
paths for sidebar organization:
tsx
const meta = {
  title: 'Components/StructuredFilter/SelectOptions',
  component: SelectOptions,
} satisfies Meta<typeof SelectOptions>;
Patterns:
PatternUse Case
Components/[ComponentName]
Single component stories
Components/[ComponentName]/States
Visual state variations
Components/[ComponentName]/Flows
User interaction flows
Features/[FeatureName]
Feature-level compositions
使用层级化的
title
路径来组织侧边栏:
tsx
const meta = {
  title: 'Components/StructuredFilter/SelectOptions',
  component: SelectOptions,
} satisfies Meta<typeof SelectOptions>;
模式:
模式使用场景
Components/[ComponentName]
单一组件的故事
Components/[ComponentName]/States
视觉状态变体
Components/[ComponentName]/Flows
用户交互流程
Features/[FeatureName]
功能级别的组合组件

Examples

示例

Example 1: Create a new story file

示例1:创建新的故事文件

User: "Create stories for the UserProfile component"
Action:
tsx
import type { Meta, StoryObj } from '@storybook/react';
import { UserProfile } from './UserProfile';

const meta = {
  title: 'Components/UserProfile',
  component: UserProfile,
} satisfies Meta<typeof UserProfile>;

export default meta;
type Story = StoryObj<typeof UserProfile>;

export const Default: Story = {};

export const WithLongName: Story = {
  args: { name: 'Alexandria Bartholomew Richardson III' },
};

export const EmptyState: Story = {
  args: { user: null },
};

export const LoadingState: Story = {
  args: { isLoading: true },
};

用户: "为UserProfile组件创建故事"
操作:
tsx
import type { Meta, StoryObj } from '@storybook/react';
import { UserProfile } from './UserProfile';

const meta = {
  title: 'Components/UserProfile',
  component: UserProfile,
} satisfies Meta<typeof UserProfile>;

export default meta;
type Story = StoryObj<typeof UserProfile>;

export const Default: Story = {};

export const WithLongName: Story = {
  args: { name: 'Alexandria Bartholomew Richardson III' },
};

export const EmptyState: Story = {
  args: { user: null },
};

export const LoadingState: Story = {
  args: { isLoading: true },
};

Example 2: Name an interactive story

示例2:为交互式故事命名

User: "Add a story where the user fills out and submits the form"
Action:
tsx
// Good - describes the user action
export const FillAndSubmit: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.type(canvas.getByLabelText('Email'), 'user@example.com');
    await userEvent.click(canvas.getByRole('button', { name: 'Submit' }));
  },
};
Not:
tsx
// Bad - exposes implementation detail
export const InteractiveFormSubmission: Story = { ... };
export const PlayFunctionSubmit: Story = { ... };
export const TestFormValidation: Story = { ... };

用户: "添加一个用户填写并提交表单的故事"
操作:
tsx
// Good - describes the user action
export const FillAndSubmit: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.type(canvas.getByLabelText('Email'), 'user@example.com');
    await userEvent.click(canvas.getByRole('button', { name: 'Submit' }));
  },
};
错误示例:
tsx
// Bad - exposes implementation detail
export const InteractiveFormSubmission: Story = { ... };
export const PlayFunctionSubmit: Story = { ... };
export const TestFormValidation: Story = { ... };

Example 3: Organize complex component stories

示例3:整理复杂组件的故事

User: "Set up stories for the DataGrid with states and interactions"
Action:
tsx
// States file: Components/DataGrid/States
export const Empty: Story = {};
export const WithSingleRow: Story = {};
export const WithPagination: Story = {};
export const DisabledState: Story = {};

// Flows file: Components/DataGrid/Flows
export const SortByColumn: Story = {};
export const FilterAndSearch: Story = {};
export const SelectMultipleRows: Story = {};
export const EditInlineCell: Story = {};

用户: "为DataGrid组件设置包含状态和交互的故事"
操作:
tsx
// States file: Components/DataGrid/States
export const Empty: Story = {};
export const WithSingleRow: Story = {};
export const WithPagination: Story = {};
export const DisabledState: Story = {};

// Flows file: Components/DataGrid/Flows
export const SortByColumn: Story = {};
export const FilterAndSearch: Story = {};
export const SelectMultipleRows: Story = {};
export const EditInlineCell: Story = {};

Example 4: Review story names for convention compliance

示例4:审核故事名称是否符合规范

User: "Review my story names"
Action: Check each export name against the three questions:
Current NameIssueSuggested Name
InteractiveDefault
Exposes implementation (
Interactive
prefix)
Default
TestSearchFlow
Exposes implementation (
Test
prefix)
SearchByKeyword
PlaySelectAll
Exposes implementation (
Play
prefix)
SelectAll
WithError
Describes state
WithError
(keep)
EmptyState
Describes state
EmptyState
(keep)
用户: "审核我的故事名称"
操作: 根据三个问题检查每个导出名称:
当前名称问题建议名称
InteractiveDefault
暴露实现细节(
Interactive
前缀)
Default
TestSearchFlow
暴露实现细节(
Test
前缀)
SearchByKeyword
PlaySelectAll
暴露实现细节(
Play
前缀)
SelectAll
WithError
描述状态
WithError
(保留)
EmptyState
描述状态
EmptyState
(保留)

Common Anti-Patterns

常见反模式

Anti-PatternWhy It's BadFix
Interactive*
prefix
Play function already signals interactivityRemove prefix
Test*
prefix
Stories aren't tests, they're demonstrationsDescribe the scenario
PlayFunction*
prefix
Implementation detailDescribe what happens
Render*
prefix
All stories renderDescribe what's rendered
Technical jargon in namesNon-technical stakeholders can't understandUse plain language
反模式弊端修复方案
Interactive*
前缀
Play函数已经表明了交互性移除前缀
Test*
前缀
故事不是测试,而是演示描述具体场景
PlayFunction*
前缀
属于实现细节描述实际发生的操作
Render*
前缀
所有故事都会渲染描述渲染的内容
名称中包含技术术语非技术利益相关者无法理解使用通俗易懂的语言

More Information

更多信息

See REFERENCE.md for detailed documentation including:
  • Complete naming patterns with examples
  • Story title hierarchy best practices
  • Code review checklist for story naming
  • Migration guide for renaming existing stories
详见REFERENCE.md中的详细文档,包括:
  • 完整的命名模式及示例
  • 故事标题层级最佳实践
  • 故事命名的代码审核清单
  • 现有故事重命名的迁移指南