跨平台与移动端 UI · 新资源

Tamagui 设计系统.

通过完整的原生组件习惯追踪板(含验证、进度和空状态恢复),了解 Tamagui 实际的 v5 令牌类别以及浅色/深色蓝色主题。

OpenDesign 指南8 个章节50 个参考条目原始应用指南
01

Tamagui 设计系统界面预览

添加习惯、标记进度、筛选未完成项目,并切换蓝色主题。

构建小习惯看板打开完整示例
Tamagui 2.7.7 原生 Web 组件,采用 v5 配置和原创本地状态。· 实现参考
02

Tamagui 设计系统设计参考

@tamagui/config/v5 和 @tamagui/themes 2.7.7 导出的值,以及已验证的原生组件约定。

v5 尺寸令牌

来源
名称 / 规则值 / 配置用途
size.$120实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
size.$228实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
size.$336实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
size.$444实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
size.$552实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
size.$664实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。

v5 间距令牌

来源
名称 / 规则值 / 配置用途
space.$12实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$1.54实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$27实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$2.510实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$313实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$3.516实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$418实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$524实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
space.$632实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。

v5 圆角令牌

来源
名称 / 规则值 / 配置用途
radius.00实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
radius.13实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
radius.25实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
radius.37实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
radius.49实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
radius.510实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。
radius.616实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同;不要将 $4 视为通用像素值。

light_blue 语义主题

来源
名称 / 规则值 / 配置用途
light_blue.backgroundhsla(207, 100%, 98%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
light_blue.backgroundHoverhsla(210, 100%, 99%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
light_blue.backgroundPresshsla(205, 92%, 95%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
light_blue.colorhsla(216, 71%, 23%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
light_blue.borderColorhsla(203, 100%, 92%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
light_blue.borderColorFocushsla(203, 100%, 92%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
light_blue.placeholderColorhsla(206, 100%, 50%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。

dark_blue 语义主题

来源
名称 / 规则值 / 配置用途
dark_blue.backgroundhsla(218, 39%, 11%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
dark_blue.backgroundHoverhsla(212, 69%, 16%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
dark_blue.backgroundPresshsla(215, 42%, 9%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
dark_blue.colorhsla(205, 100%, 88%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
dark_blue.borderColorhsla(209, 100%, 19%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
dark_blue.borderColorFocushsla(209, 100%, 19%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。
dark_blue.placeholderColorhsla(206, 100%, 50%, 1)从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。

系统字体角色

来源
名称 / 规则值 / 配置用途
body.family-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serifv5 系统字体栈无需请求远程字体。
body.$213px / 20px字号与行高配对构成字体角色,独立于具有相同标签的组件尺寸令牌。
body.$314px / 21px字号与行高配对构成字体角色,独立于具有相同标签的组件尺寸令牌。
body.$415px / 23px字号与行高配对构成字体角色,独立于具有相同标签的组件尺寸令牌。
body.$516px / 24px字号与行高配对构成字体角色,独立于具有相同标签的组件尺寸令牌。
body.$618px / 27px字号与行高配对构成字体角色,独立于具有相同标签的组件尺寸令牌。
body.$826px / 38px字号与行高配对构成字体角色,独立于具有相同标签的组件尺寸令牌。

原生组合约定

来源
名称 / 规则值 / 配置用途
createTamaguidefaultConfig from @tamagui/config/v5在 React 外部创建一个配置实例;getCSS() 提供 Web 主题 CSS。
TamaguiProviderconfig + defaultTheme应用选择浅色或深色外观,同时保留看板状态。
Themename="blue"解析当前外观对应的蓝色子主题。
Checkboxchecked + onCheckedChange看板仅将 value === true 视为已完成;不确定状态不代表完成。
Inputvalue + onChangeText受控草稿、去除首尾空格后校验,并明确处理重复项。
Progressvalue from 0 to 100进度指示器根据已完成数除以总行数计算得出。
YStack / XStackdirectional layout with token gap保持阅读布局自适应,无需另写仿制样式表。
03

Tamagui 设计系统完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-tamagui.md

完整指导、实现起点和源代码链接。

下载指南

Tamagui 设计系统版本化配置与 CSS

使用指定的 v5 预设

此示例固定使用 tamagui 和 @tamagui/config 的 2.7.7 版本,并从 @tamagui/config/v5 导入 defaultConfig。配置名称是 v5,并非 npm 包的主版本号。混淆这两个数字会导致读者使用错误的安装命令。createTamagui 在组件外运行一次,其生成的 CSS 会在界面板渲染前插入,确保主题变量和原生样式在 Web 上有实际定义。

摘自本 OpenDesign 指南

明确说明小型配置覆写

提供的源代码将 onlyAllowShorthands 设为 false,因为此教学示例使用 padding 和 backgroundColor 等易读的完整属性名。这是基于预设做出的应用层选择。v5 基础配置不包含动画驱动程序,此示例也不会凭空添加驱动程序或声称支持动画过渡。简单的进度和复选框交互无需额外添加动画依赖。

Tamagui 设计系统尺寸、间距与圆角令牌

不要混淆名称相同的令牌

在固定使用的 v5 配置中,尺寸令牌 $4 为 44,间距令牌 $4 为 18,圆角令牌 4 为 9。因此,组件尺寸、布局间距和圆角不能通过同一套乘数规则换算。参考内容分别列出各个类别,示例则通过实际的 Tamagui 属性使用对应类别的值。这比罗列配置中并未采用的通用 4px 增量更实用。

  • size.$4 = 44
  • space.$4 = 18
  • radius.4 = 9
  • 正文文本字体 $4 = 15px,行高为 23px

字号比例也应单独处理

正文文本字体 $4 为 15px,行高为 23px,而组件尺寸 $4 仍为 44。系统字体栈由 v5 提供,无需下载字体文件。H1、H2 和 Text 会继承其原生字体上下文;源代码中的显式 fontSize 和 lineHeight 值决定了原界面板的层级。外层宽度 880px 是本地布局选择,并非全局 Tamagui 令牌。

Tamagui 设计系统语义主题与外观

将浅色或深色外观与蓝色子主题组合

TamaguiProvider 接收所选的 defaultTheme,Theme name="blue" 则解析对应的子主题。源代码使用 background、backgroundHover、color 和 borderColor 角色,避免在整个组件树中反复填写十六进制颜色值。表格列出实际的 light_blue 和 dark_blue 值,便于读者比较解析后的配置,而不是假设品牌配色只有一套固定值。

切换外观时保留界面板状态

dark 标记与行数据、输入草稿和筛选条件相互独立。切换外观会更新原生组件,同时保留界面板内容。按钮和复选框可以选择各自的组件子主题值,因此它们计算出的颜色不一定与父级背景令牌相同。将层级简化为自定义 CSS 前,请先检查渲染后的状态。

Tamagui 设计系统复选框与派生进度

将完成状态保存在同一组行数据中

每一行都有稳定的 ID、易读的文本和 done 布尔值。Checkbox 接收 checked 和 onCheckedChange;只有值严格等于 true 时,项目才会标记为已完成。Checkbox.Indicator 用于显示勾选标记。相邻文本和无障碍名称都指向同一项习惯,删除线则以视觉方式重复呈现已完成状态。源代码不会单独创建一个可能与行数据不同步的计数。

根据整个界面板计算进度

Tamagui 设计系统草稿验证与重复项处理

添加真正受控的输入框

Input 通过 value 和 onChangeText 保存当前草稿。“添加习惯”操作会去除首尾空白,并在输入为空时显示提示、设置 aria-invalid 并提供错误说明。空内容提交后,焦点会返回输入框。不区分大小写的重复项检查可防止添加文本相同的第二行,并保留草稿以供修改。这些规则属于原界面板,而非库本身。

仅在成功添加后更新界面板

有效的草稿会添加一行新的未完成习惯、清空输入并移除错误。进度分母会立即变化,因为它是根据新列表计算得出的。添加习惯不会注册提醒,也不会创建账户。看板数据有意保存在本地 React 状态中,重新加载文档后会恢复为示例内容。

Tamagui 设计系统:筛选视图与空状态恢复

明确筛选范围

“仅显示未完成项”会隐藏已完成的行,但这些行仍保留在列表中。如果此视图中没有剩余内容,空状态文案会说明完整列表仍然存在,并提供直接返回的操作。这是由用户选择产生的有效空状态,而不是通过切换来替换任意占位卡片的装饰性控件。

让重置与外观设置彼此独立

“重置示例看板”会恢复初始的三行内容、清空草稿和错误,并返回完整列表,但不会改变当前外观。由于每项变化都是显式状态,重置时无需重新加载文档,也无需丢弃已配置的提供程序。主题与内容恢复可以分别测试。

Tamagui 设计系统:响应式堆叠与无障碍阅读

让堆叠内容决定高度

YStack 用于布局主要阅读内容流,XStack 用于对齐标题控件、复选框行和操作按钮。控件组会自动换行,而不是强制使用固定的桌面宽度。外层容器最大宽度为 880px,并使用真实的 $4 间距令牌设置内边距。每一行都允许文本收缩和换行,同时确保在 280px 及更大的测试宽度下仍可使用控件。

在重新排版后测试交互

浏览器测试会先添加一个习惯、将其标记为已完成、筛选列表并切换外观,然后测量内容是否溢出。仅截取初始布局的屏幕截图,无法发现错误提示、长标签或筛选状态是否会破坏窄屏布局。测试还实际检查了原生复选框语义和可见文本,以及派生的进度值,而不是只确认它们存在就假定功能正常。

Tamagui 设计系统:完整的浏览器构建

提供程序、CSS 和构建定义

这三个提供的文件足以构成本地 Web 示例。JSX 包含提供程序、一份配置、生成的主题 CSS 和完整看板。build.mjs 固定了 Web 目标和生产环境,并为其他仅限浏览器的环境读取提供空的 process.env 回退值。缺少最后这项定义时,即使代码可以编译,这个纯浏览器打包也可能因 process is not defined 而失败。

  1. 将 tamagui.jsx、build.mjs 和 index.html 保存在同一目录中。
  2. 安装固定版本的 React 和 Tamagui 包。
  3. 构建并提供本地目录。
  4. 测试空内容和重复项的添加、完成状态、筛选、主题与重置。

将原生端与 Web 端的采用方式分开

Tamagui 设计系统:组件示例

tamagui.jsx

配置、生成的 CSS、原生组件与完整的看板状态。

jsx
import React,{useState} from 'react';import{createRoot}from'react-dom/client';
import{createTamagui,TamaguiProvider,Theme,YStack,XStack,Text,H1,H2,Button,Input,Checkbox,Progress,Separator}from'tamagui';import{defaultConfig}from'@tamagui/config/v5';
const config=createTamagui({...defaultConfig,settings:{...defaultConfig.settings,onlyAllowShorthands:false}});const sheet=document.createElement('style');sheet.textContent=config.getCSS();document.head.append(sheet);
const initial=[{id:1,text:'Read ten pages',done:false},{id:2,text:'Step outside for a break',done:true},{id:3,text:'Write one useful note',done:false}];
function App(){const[dark,setDark]=useState(false),[rows,setRows]=useState(initial),[draft,setDraft]=useState(''),[error,setError]=useState(''),[filter,setFilter]=useState(false);const done=rows.filter(x=>x.done).length;let shown=rows.filter(x=>!filter||!x.done);function add(){let text=draft.trim();if(!text){setError('Write a small habit before adding it.');document.querySelector('#habit-input')?.focus();return}if(rows.some(x=>x.text.toLowerCase()===text.toLowerCase())){setError('That habit is already in this list.');return}setRows([...rows,{id:Date.now(),text,done:false}]);setDraft('');setError('')}return <TamaguiProvider config={config} defaultTheme={dark?'dark':'light'}><Theme name="blue"><YStack backgroundColor="$background" color="$color" padding="$4" gap="$4" maxWidth={880} margin="auto" width="100%" minHeight={0}><XStack justifyContent="space-between" alignItems="center" flexWrap="wrap" gap="$3"><Text fontSize="$2" fontWeight="700">TAMAGUI / ORIGINAL HABIT BOARD</Text><Button size="$3" onPress={()=>setDark(!dark)}>{dark?'Light appearance':'Dark appearance'}</Button></XStack><H1 fontSize="$8" lineHeight="$8">A little progress, every day.</H1><Text fontSize="$4" lineHeight="$5">A local board built with Tamagui 2.7.7 and its v5 blue theme. Your changes stay in this page; no account or daily reminder is connected.</Text><YStack backgroundColor="$backgroundHover" borderWidth={1} borderColor="$borderColor" borderRadius="$4" padding="$4" gap="$3"><XStack justifyContent="space-between" gap="$3" flexWrap="wrap"><H2 fontSize="$5">Today’s small steps</H2><Text id="progress-count" aria-live="polite">{done} of {rows.length} complete</Text></XStack><Progress value={rows.length?done/rows.length*100:0} size="$2" aria-label="Completed habits"><Progress.Indicator animation={undefined}/></Progress><Button size="$3" alignSelf="flex-start" onPress={()=>setFilter(!filter)}>{filter?'Show all habits':'Show unfinished only'}</Button><Separator/>{shown.length?shown.map(row=><XStack key={row.id} gap="$3" alignItems="center" paddingVertical="$2"><Checkbox id={'habit-'+row.id} checked={row.done} onCheckedChange={value=>setRows(rows.map(x=>x.id===row.id?{...x,done:value===true}:x))} aria-label={row.text} size="$4"><Checkbox.Indicator><Text fontWeight="700">✓</Text></Checkbox.Indicator></Checkbox><Text flex={1} fontSize="$4" lineHeight="$5" textDecorationLine={row.done?'line-through':'none'} opacity={row.done?.65:1}>{row.text}</Text></XStack>):<YStack gap="$3"><Text fontWeight="700">Nothing unfinished in this view</Text><Text>All your habits remain in the full list. You can revisit any completed item.</Text><Button onPress={()=>setFilter(false)}>Return to all habits</Button></YStack>}</YStack><YStack gap="$3"><Text htmlFor="habit-input" tag="label" fontWeight="700">Add one small habit</Text><Input id="habit-input" value={draft} onChangeText={v=>{setDraft(v);setError('')}} placeholder="For example, stretch for five minutes" aria-describedby={error?'habit-error':undefined} aria-invalid={!!error} onKeyPress={e=>{if(e.nativeEvent.key==='Enter')add()}}/><Text id="habit-error" color="$color" aria-live="polite">{error}</Text><XStack gap="$3" flexWrap="wrap"><Button theme="active" onPress={add}>Add habit</Button><Button onPress={()=>{setRows(initial);setDraft('');setError('');setFilter(false)}}>Reset sample board</Button></XStack></YStack><Text fontSize="$2" lineHeight="$3">Native Checkbox, Input, Button and Progress components; original board content and state. Theme changes preserve the current board.</Text></YStack></Theme></TamaguiProvider>}
createRoot(document.getElementById('root')).render(<App/>);

代码参考

  • 请将这三个完整文件配套使用。

build.mjs

测试所用打包文件的浏览器环境定义。

javascript
import {build} from 'esbuild';
await build({entryPoints:['tamagui.jsx'],bundle:true,minify:true,outfile:'tamagui.bundle.js',define:{'process.env.NODE_ENV':'"production"','process.env.TAMAGUI_TARGET':'"web"','process.env':'{}'}});

代码参考

  • 请将这三个完整文件配套使用。

index.html

独立的根文档与打包文件导入。

html
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Small habits board</title><style>body{margin:0}*{box-sizing:border-box}button,input{max-width:100%}</style></head><body><div id="root"></div><script src="./tamagui.bundle.js"></script></body></html>

代码参考

  • 请将这三个完整文件配套使用。
04

Tamagui 设计系统:AI Agent 设置

实现起点

先保存提供的文件,然后打开 http://localhost:8000/。此设置专用于浏览器。

sh
npm init -y
npm install [email protected] [email protected] [email protected] @tamagui/[email protected]
npm install --save-dev esbuild
node build.mjs
python3 -m http.server 8000

适用于你项目的提示词

Agent 提示词
使用 v5 预设,实现完整的 Tamagui 2.7.7 Web 习惯看板。保持尺寸、间距、圆角和字体令牌类别彼此独立;保留生成的主题 CSS、浅色与深色蓝色子主题、受控复选框、去除首尾空格与重复项验证、包含所有行的进度分母、未完成视图的恢复功能,以及不改变外观的重置功能。
05

Tamagui 设计系统:来源与范围

使用 v5 预设的实际 Tamagui 2.7.7 Web 组件。习惯看板及其状态规则为原创 OpenDesign 代码;未连接账户、提醒或原生设备行为。