component-variants
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseComponent Variants Pattern
组件变体模式
Create matching light and dark variants of UI components using a systematic color token approach.
使用系统化的颜色令牌方法创建匹配的UI组件亮色和暗色变体。
Pattern Overview
模式概述
- Create paired components: and
ComponentLightComponentDark - Mirror the structure exactly between variants
- Map colors systematically using the token table below
- Export a unified component that renders both or accepts a prop
variant
- 创建配对组件:和
ComponentLightComponentDark - 变体之间的结构完全镜像
- 使用下方的令牌表系统化映射颜色
- 导出一个可渲染两种变体或接受属性的统一组件
variant
Color Token Mapping
颜色令牌映射
Basic Tokens
基础令牌
| Semantic Use | Light Mode | Dark Mode |
|---|---|---|
| Card background | | |
| Card border | | |
| Content area | | |
| Primary text | | |
| Secondary text | | |
| Muted text | | |
| Icon color | | |
| Tag background | | |
| Tag text | | |
| Accent background | | |
| Accent text | | |
| Shadow | | |
| Hover background | | |
| 语义用途 | 亮色模式 | 暗色模式 |
|---|---|---|
| 卡片背景 | | |
| 卡片边框 | | |
| 内容区域 | | |
| 主文本 | | |
| 次要文本 | | |
| 弱化文本 | | |
| 图标颜色 | | |
| 标签背景 | | |
| 标签文本 | | |
| 强调背景 | | |
| 强调文本 | | |
| 阴影 | | |
| 悬停背景 | | |
Gradient & Nested Card Tokens
渐变与嵌套卡片令牌
| Semantic Use | Light Mode | Dark Mode |
|---|---|---|
| Outer card gradient | | |
| Outer card border | | |
| Outer card shadow | | |
| Inner media border | | |
| 语义用途 | 亮色模式 | 暗色模式 |
|---|---|---|
| 外层卡片渐变 | | |
| 外层卡片边框 | | |
| 外层卡片阴影 | | |
| 内层媒体边框 | | |
Badge Tokens
徽章令牌
| Semantic Use | Light Mode | Dark Mode |
|---|---|---|
| Success badge bg | | |
| Success badge text | | |
| 语义用途 | 亮色模式 | 暗色模式 |
|---|---|---|
| 成功徽章背景 | | |
| 成功徽章文本 | | |
Separator Tokens
分隔符令牌
| Semantic Use | Light Mode | Dark Mode |
|---|---|---|
| Dot separator | | |
| Border separator | | |
| 语义用途 | 亮色模式 | 暗色模式 |
|---|---|---|
| 点分隔符 | | |
| 边框分隔符 | | |
Implementation Template
实现模板
tsx
// 1. Create the Light variant
function ComponentLight() {
return (
<div className="bg-[#f8f8f8] rounded-xl border border-zinc-200/80 shadow-lg shadow-zinc-200/50">
<div className="bg-white px-4 py-4">
<span className="text-zinc-900">Primary content</span>
<span className="text-zinc-500">Secondary content</span>
</div>
</div>
);
}
// 2. Create the Dark variant (mirror structure, swap tokens)
function ComponentDark() {
return (
<div className="bg-zinc-800 rounded-xl border border-zinc-700/80 shadow-lg shadow-black/30">
<div className="bg-zinc-900 px-4 py-4">
<span className="text-zinc-100">Primary content</span>
<span className="text-zinc-500">Secondary content</span>
</div>
</div>
);
}
// 3. Export unified component
export function Component({ variant = "light" }: { variant?: "light" | "dark" }) {
return variant === "dark" ? <ComponentDark /> : <ComponentLight />;
}tsx
// 1. Create the Light variant
function ComponentLight() {
return (
<div className="bg-[#f8f8f8] rounded-xl border border-zinc-200/80 shadow-lg shadow-zinc-200/50">
<div className="bg-white px-4 py-4">
<span className="text-zinc-900">Primary content</span>
<span className="text-zinc-500">Secondary content</span>
</div>
</div>
);
}
// 2. Create the Dark variant (mirror structure, swap tokens)
function ComponentDark() {
return (
<div className="bg-zinc-800 rounded-xl border border-zinc-700/80 shadow-lg shadow-black/30">
<div className="bg-zinc-900 px-4 py-4">
<span className="text-zinc-100">Primary content</span>
<span className="text-zinc-500">Secondary content</span>
</div>
</div>
);
}
// 3. Export unified component
export function Component({ variant = "light" }: { variant?: "light" | "dark" }) {
return variant === "dark" ? <ComponentDark /> : <ComponentLight />;
}Helper Components Pattern
辅助组件模式
When components have repeated sub-elements, create paired helpers:
tsx
interface InfoRowProps {
icon: React.ReactNode;
label: string;
value: React.ReactNode;
}
function InfoRowLight({ icon, label, value }: InfoRowProps) {
return (
<div className="flex items-center gap-3 py-1">
<span className="text-zinc-400">{icon}</span>
<span className="text-zinc-500 text-sm w-32">{label}</span>
<div className="flex-1">{value}</div>
</div>
);
}
function InfoRowDark({ icon, label, value }: InfoRowProps) {
return (
<div className="flex items-center gap-3 py-1">
<span className="text-zinc-500">{icon}</span>
<span className="text-zinc-500 text-sm w-32">{label}</span>
<div className="flex-1">{value}</div>
</div>
);
}当组件包含重复子元素时,创建配对的辅助组件:
tsx
interface InfoRowProps {
icon: React.ReactNode;
label: string;
value: React.ReactNode;
}
function InfoRowLight({ icon, label, value }: InfoRowProps) {
return (
<div className="flex items-center gap-3 py-1">
<span className="text-zinc-400">{icon}</span>
<span className="text-zinc-500 text-sm w-32">{label}</span>
<div className="flex-1">{value}</div>
</div>
);
}
function InfoRowDark({ icon, label, value }: InfoRowProps) {
return (
<div className="flex items-center gap-3 py-1">
<span className="text-zinc-500">{icon}</span>
<span className="text-zinc-500 text-sm w-32">{label}</span>
<div className="flex-1">{value}</div>
</div>
);
}Checklist
检查清单
- Light and dark variants have identical structure
- All color classes mapped according to token table
- Text contrast meets accessibility guidelines
- Shadows appropriate for each theme
- Hover/focus states defined for both themes
- 亮色和暗色变体结构完全一致
- 所有颜色类均根据令牌表映射
- 文本对比度符合无障碍指南
- 阴影适配对应主题
- 两种主题均定义了悬停/聚焦状态