mcpField
A
atomic-design

atomic-design

github.com/jwilger设计与 UI5243 次安装17 周前更新
代码仓库

关于 atomic-design

Atomic Design 是一种将用户界面组织为原子、分子、有机体和模板的技能。它指导团队自下而上构建可复用的展示组件,使用设计令牌和组合,而非继承。

主要功能

  1. 01四层组件层级
  2. 02自下而上的组件组合
  3. 03展示组件的职责边界
  4. 04用设计令牌管理视觉属性
  5. 05以组合替代继承

适用场景

  1. 01组织 UI 组件库
  2. 02从小型元素构建可复用页面布局
  3. 03分离界面渲染与数据获取及业务逻辑

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jwilger/agent-skills --skill atomic-design

安装后在 Claude Code 中输入/atomic-design确认已加载。

详细介绍

原子设计

价值: 简洁与沟通。通过小型、命名明确且可组合的部分来构建 UI,让团队中的每个人都能理解界面,并避免单体组件带来的复杂性。

目的

介绍如何将 UI 组件组织成复杂度递增的层级:原子、分子、有机体和模板。每个层级都有明确的职责和组合规则。最终形成一个组件系统,其中的每个部分都可复用、可单独测试,并采用团队共用的词汇命名。

实践

由下而上构建四个层级

从最小的可复用元素开始,逐层向上组合。不要跳过任何层级。

四个层级:

  1. **原子:**不可再分的 UI 元素。按钮、输入框、标签、图标。一个视觉元素,一项职责。原子的所有视觉属性(颜色、间距、字体排版)都引用设计令牌。

  2. **分子:**作为一个整体发挥作用的小型原子组。表单字段(标签 + 输入框 + 错误消息)。搜索栏(输入框 + 按钮 + 图标)。每个分子对应一种交互模式。

  3. **有机体:**由分子和原子组成、构成界面中独立区域的复杂组件。导航页眉、完整表单、数据表格。每个有机体对应一个功能区域。

  4. **模板:**页面级布局,将有机体排列成完整视图。仪表板模板、列表详情模板。模板定义结构和内容槽位,不定义具体数据。

示例:

Atom: Button, Input, Label, ErrorMessage
Molecule: FormField (Label + Input + ErrorMessage)
Organism: LoginForm (FormField + FormField + Button)
Template: AuthPage (Header + LoginForm + Footer)

应该:

  • 构建新 UI 时,从原子开始
  • 根据组件的本质命名,而不是根据它显示的数据命名
  • 将原子控制在 50 行以内,分子控制在 100 行以内

不应该:

  • 直接用原始标记构建有机体——先提取原子
  • 创建不组合系统中原子的分子
  • 在有机体尚未创建时就直接构建模板
保持组件仅负责呈现

组件负责渲染 UI。它们通过 props 接收数据。它们不获取数据、不管理业务逻辑,也不持有应用状态。

  1. 通过 props 或等效方式传递所有数据
  2. 为用户操作发出事件——不要处理副作用
  3. 将数据容器与呈现组件分开

示例:

Presentational (good):
  UserCard({ name, email, avatar }) -> renders UI

Container (separate):
  UserCardContainer() -> fetches data, passes to UserCard

不应该:

  • 在原子、分子或有机体中发起 API 调用
  • 将组件与特定数据源耦合
  • 在同一个组件中混合渲染逻辑与业务逻辑
所有视觉属性都使用设计令牌

将每项设计决策(颜色、间距、字体排版、阴影、圆角)提取为命名令牌。组件引用令牌,绝不使用原始值。

  1. 创建新设计系统时,第一步就定义令牌
  2. 组件中的每种颜色、间距值和字号都必须来自令牌
  3. 更改令牌会更新所有引用它的组件

示例:

/* Tokens */
--color-primary: #0066cc;
--spacing-sm: 8px;
--spacing-md: 16px;

/* Component uses tokens, not values */
.button { background: var(--color-primary); padding: var(--spacing-sm); }

不应该:

  • 在任何组件中硬编码 #0066cc 或 8px
  • 为单个组件创建一次性令牌名称
  • 定义从未使用的令牌(令牌应当发挥作用)
组合,不要继承

通过嵌套更简单的组件来构建复杂组件。不要通过类继承或层层传递 props 来扩展基础组件。

  1. 通过传递 children 或槽位来组合布局
  2. 保持组件树扁平——优先使用同级组件,而不是深层嵌套
  3. 需要变体时,用原子组合出新的分子,而不是给现有分子添加标记

应该:

  • IconButton = Icon + Button(组合)
  • Card > CardHeader + CardBody(槽位)

不应该:

  • FancyButton extends Button(继承)
  • 用一个包含 15 个变体 props 的 Button 组件

执行说明

在所有模式下均为建议。组件层级与令牌规范由开发者自行执行。

硬性约束:

  • 仅引用令牌(组件中不得使用原始值):[RP]

约束

  • “绝不跳过层级”:实际上属于分子(由多个视觉元素组成)的原子,即使你把它命名为“原子”,也跳过了层级。分类依据是组件的实际属性,而不是它所在的目录。如果你的“原子”包含 3 个带布局逻辑的内部元素,它就是一个分子。
  • “不使用原始值”:为每个唯一值定义一个令牌,却从不复用这些令牌,这就失去了令牌的意义。令牌的作用是复用并保持一致性。如果某个令牌只使用了一次,请自问:这个值是否应该与其他组件共享?如果是,令牌定义正确。如果不是,这个值可能应该来自更通用的令牌(例如,使用 spacing-md,而不是 card-header-padding-top)。
  • 展示层边界:展示层意味着:通过 props 传入数据,通过回调向外发送事件。筛选要展示的数据属于展示层(这是视图层关注的事项)。获取数据、修改状态或调用 API 则不属于展示层。判断标准:使用模拟 props 的 Storybook 故事能否让这个组件呈现完全相同的效果?如果它需要运行中的后端,就不属于展示层。

验证

按照此技能的指导完成工作后,请验证:

  • 每个 UI 元素都能追溯到一个原子(organism/template 中没有原始标记)
  • 已定义设计令牌,且组件引用了这些令牌(没有硬编码值)
  • 每个组件都承担与其层级相符的单一职责
  • 组件属于展示层(传入数据,向外发送事件)
  • 层级已记录,或能从目录结构中明确看出

如果任何一项不符合,请在继续之前重新检查相关实践。

依赖项

此技能可独立使用。如需增强工作流,可与以下内容集成:

  • design-system: 设计系统规范提供此技能将在代码中实现的令牌定义、组件目录和层级。
  • domain-modeling: 来自领域模型的读取模型定义组件通过 props 接收的数据。
  • tdd: 在每个层级单独测试组件——原子测试、分子测试、organism 测试。
  • event-modeling: 事件建模会话中的线框图可确定需要哪些组件。

缺少依赖项?使用以下命令安装:

npx skills add jwilger/agent-skills --skill tdd

评论

支持 Markdown