# SEEK Braid 设计系统

## SEEK Braid 设计系统界面预览

编辑并应用职位或城市查询，检查无结果状态，并清空输入框和已应用的搜索条件。

## SEEK Braid 设计系统设计参考

当前 Braid 组件和 CSS 参考资料。命名尺寸通过所选主题解析；此处不会推断未经验证的像素等效值，也不会虚构生成的 CSS 变量名称。原生示例明确选择 seekJobs。

### 响应式断点

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| mobile | 0 | 基础样式。 |
| tablet | 740px | 第一个较大视口条件。 |
| desktop | 992px | 桌面视口条件。 |
| wide | 1200px | 宽屏视口条件。 |
### 主题变量 API

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| vars.space.medium | Theme-scoped CSS expression | 直接使用；进行算术运算需使用 calc。 |
| vars.space.gutter | Theme gutter expression | 版面间距。 |
| vars.backgroundColor.body | Theme body background | 页面界面表面。 |
| vars.backgroundColor.surface | Theme surface background | 容器表面。 |
| vars.backgroundColor.brandAccent | Theme brand action background | 不要假定存在通用十六进制值。 |
| vars.foregroundColor.neutral | Theme text role | 主要内容。 |
| vars.foregroundColor.secondary | Theme secondary role | 元数据。 |
| vars.borderColor.focus | Theme focus role | 可见焦点。 |
| vars.borderRadius.standard | Theme radius expression | 标准形状。 |
### 盒式布局 API

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| component | div by default | 按需选择语义化的 main、section、form。 |
| padding | Named space, responsive object allowed | 示例：移动端 medium / 平板端 xlarge。 |
| gap | Named spacing values | 同级元素间距。 |
| background="customDark" | Context for custom dark surfaces | 启用匹配的前景行为。 |
| borderRadius | none / small / standard / large / xlarge / full | 由主题解析的形状。 |
### 文本与字段规范

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| label / secondaryLabel / tertiaryLabel | Three label levels | 用途、可选上下文、辅助信息。 |
| description | Below-label context | 字段获得焦点时播报。 |
| message + tone | critical / positive / caution / neutral | 说明字段状态。 |
| onClear | Callback required for clear action | 应用重置受控值。 |
| clearLabel | Accessible clear-control label | 本地化。 |
### 按钮的视觉强调与行为

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| variant | solid / ghost / soft / transparent | 视觉强调。 |
| tone | brandAccent / formAccent / critical / neutral | 操作含义。 |
| No explicit tone | Neutral ghost by default | 低调的基准样式。 |
| Explicit tone, no variant | Solid default | 同时指定两者以消除歧义。 |
| size | standard / small | 支持的尺寸。 |
| loading | Also disables interaction | 仅用于确有待处理工作的情况。 |
| Ordinary disabled | Not supported | 允许用户尝试，并说明错误原因。 |
### 文本语义

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| size | large / standard / small / xsmall | 主题的类型比例。 |
| weight | regular / medium / strong | 文本强调。 |
| component="p" | Paragraph element | 视觉类型与语义彼此独立。 |
| maxLines | Number | 限制用户生成内容的可见范围。 |
| tone="secondary" | Metadata emphasis | 不能替代错误角色。 |
## SEEK Braid 设计系统完整指南

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

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

## SEEK Braid 设计系统：选定主题后，视觉规范随之确定

### Provider、重置样式与生成的变量协同工作

> Braid 面向 SEEK Group 的多个主题。其变量 API 包含带作用域的 CSS 表达式，因此 vars.space.medium 这样的名称是稳定的引用，而生成的自定义属性标识符不应手动复现。本例通过 BraidProvider 选择 seekJobs。

必须先于其他 Braid 样式导入重置样式。在嵌入式应用中，styleBody={false} 可避免 Provider 更改宿主页面 body 的背景和间距。此选项并不能免除主题上下文的必要性。

阅读配套规范

## SEEK Braid 设计系统：响应式值使用主题中命名的间距

### 保留四个实际断点条件

共用的断点阈值为：mobile 从零开始，tablet 为 740px，desktop 为 992px，wide 为 1200px。原生示例通过响应式属性对象，在 tablet 断点调整内边距，不会为同一变化重复编写 CSS 媒体查询。

此处并未将主题的 medium 间距臆测为某个像素值。间距优先使用 Box 和 Stack。当布局无法通过这些组件实现时，可将 vars 作为更底层的备用方案；由于其值是 CSS 表达式，乘法应使用 calc，而不是 JavaScript 数值运算。

阅读配套规范

## SEEK Braid 设计系统：文本角色会承接周围的颜色上下文

### 分别选择层级与语义

Text 提供命名尺寸和字重，Heading 则用于表达标题层级。职位所在城市可以使用次要色调，但职位标题应保持足够醒目，以便识别搜索结果。如果内容是段落，可通过 component="p" 让 Text 渲染为段落，而不是仅因默认外观而选择某个 HTML 元素。

在深色背景上下文中，Braid 会调整前景色调。使用原始图片或自定义背景时，可通过 Box 的 customDark 上下文说明这种关系。不能假定手动设置颜色的 div 也具备相同的上下文行为。

阅读配套规范

## SEEK Braid 设计系统：tone 表示含义，variant 表示强调程度

### 将品牌强调色留给搜索操作

本例明确为 Search jobs 搭配 solid variant 和 brandAccent。Clear search 是更克制的 ghost 操作。formAccent 可用于强调可重复执行的表单操作；critical 用于表示破坏性后果，不应仅为提高普通控件的醒目程度而使用。

Braid 的默认行为需要留意：未另行指定时，中性按钮为 ghost；设置 tone 后，隐式 variant 会变为 solid。在关键操作中明确写出这两个属性，有助于保持预期层级清晰。Actions 会处理常见的移动端纵向排列和较宽视口下的行内排列。

阅读配套规范

## SEEK Braid 设计系统：提供可操作的错误信息，胜过禁用按钮

### 遵循受控字段的约定

TextField 的 onChange 回调会接收 React 输入事件。示例读取 event.target.value 并保存为草稿文本，只有用户触发 Search 后才应用搜索内容。示例还提供了清除回调，因为该控件无法自行清除应用状态。

message 用于说明查询为空的错误，critical tone 则提供其视觉状态。description 用于持久显示的上下文。Braid 不支持常规的禁用状态 Button；操作会保持可用，让访客能够了解如何继续。离线预览还会将焦点移至无效字段。

1. 将编辑内容保留在草稿查询状态中。

2. 点击 Search 时，要求查询内容经去除首尾空格后不为空。

3. 失败时显示有帮助的关键信息。

4. 成功后应用查询，并明确显示无匹配结果的状态。

阅读配套规范

## SEEK Braid 设计系统：此示例仅搜索原始数据

### 本地搜索结果不代表实时职位空缺

预览中包含三条虚构的职位记录，附有职位、城市和工作场所元数据。搜索会忽略大小写，对比职位名称和城市。它不会获取 SEEK 的实时职位列表，搜索结果也会标明为示例。

将草稿文本与已应用的结果分开，可以让交互状态一目了然：编辑职位不会在按下 Search 之前悄然替换当前结果。清除搜索会重置这两个值。没有匹配项时，结果列表会说明这一情况，同时保持搜索控件可用。

- 应用查询后显示结果数量。

- 编辑过程中，让上一次已应用的查询保持清晰可见。

- 不要在示例列表中添加没有实际作用的 Apply 提交按钮。

阅读配套规范

## SEEK Braid 设计系统：使用可提取 Braid 样式的构建流程

### 安装软件包只是配置工作的一部分

官方配置针对 sku 进行了优化。在自定义打包工具中使用 Braid 的 Vanilla Extract 样式，需要集成构建流程；重置样式和选定主题也必须按文档所述顺序引入应用。所提供的代码是适用于现有兼容 sku 项目的完整入口，并不意味着随便放入一个 script 标签就能运行 Braid。

Braid 会执行开发环境断言，并根据环境发出警告。官方构建指南建议在生产环境构建时移除断言并替换环境变量。请在实现流程中考虑这一点；本页的离线 HTML 示例不依赖此类软件包构建。

阅读配套规范

## SEEK Braid 设计系统组件示例

### 完整的独立交互示例

将完整文档保存为 index.html 并在浏览器中打开。这是对 Braid 搜索组合方式、层级和断点指南的独立离线 HTML 解读；不接入实时 SEEK 数据，也不运行 Braid。预览配色和实际间距均为应用自行选择。

```
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Braid sample job search interpretation</title><style>*{box-sizing:border-box}body{margin:0;background:#f5f5f5;color:#222;font:16px/1.5 system-ui,sans-serif}header{background:white;padding:16px 32px;border-bottom:1px solid #ddd;display:flex;align-items:center;justify-content:space-between}header strong{color:#0d3880;font-size:20px}header span{font-size:14px;color:#666}.hero{background:#0d3880;color:white;padding:32px}.hero-inner{max-width:980px;margin:auto}h1{font-size:32px;line-height:1.2;margin:0 0 24px}form{display:grid;grid-template-columns:1fr auto auto;gap:16px;align-items:end}label{display:block;font-weight:600;margin-bottom:8px}input{height:48px;border:1px solid #aaa;border-radius:4px;padding:10px 12px;font:inherit;width:100%;min-width:0;color:#222}input[aria-invalid=true]{border:2px solid #c90040}button{height:48px;border:1px solid transparent;border-radius:4px;font:600 16px/1.2 system-ui;padding:0 24px;cursor:pointer}.search{background:#e60278;color:white}.clear{background:transparent;color:white;border-color:white}button:focus-visible,input:focus-visible{outline:3px solid #69d8ff;outline-offset:3px}.error{background:white;color:#b70040;padding:8px 12px;margin:16px 0 0;border-radius:4px}.error:empty{display:none}.help{font-size:14px;color:#e4eaf6;margin:16px 0 0}main{max-width:1044px;margin:32px auto;padding:0 32px}.results-head{display:flex;justify-content:space-between;gap:16px;margin-bottom:20px}h2{font-size:24px;line-height:1.3;margin:0 0 8px}.applied{font-size:14px;color:#555}article{display:grid;grid-template-columns:1fr 100px;gap:24px;padding:24px;background:white;border:1px solid #ddd;border-radius:4px;margin-bottom:16px}.company{font-size:14px;color:#555}.meta{margin:16px 0;display:flex;gap:8px;flex-wrap:wrap}.meta span{background:#f0f4fb;padding:4px 8px;font-size:12px;border-radius:4px}article p{margin:0;color:#555;font-size:14px}.monogram{background:#f1e5f4;color:#673b78;height:72px;width:72px;border-radius:12px;display:grid;place-items:center;font-weight:700;font-size:24px;justify-self:end}.monogram.blue{color:#0d3880;background:#e4efff}.monogram.green{color:#326342;background:#e8f4eb}.notice{background:white;border:1px solid #ddd;padding:24px}.boundary{font-size:12px;color:#666;margin:24px 0}@media(max-width:739px){header{padding:16px}header span{display:none}.hero{padding:24px 16px}h1{font-size:28px}form{grid-template-columns:1fr;gap:12px}form button{width:100%}main{padding:0 16px;margin:24px auto}article{padding:20px;grid-template-columns:1fr 48px;gap:12px}.monogram{height:48px;width:48px;font-size:18px}article h2{font-size:20px}.results-head{display:block}}</style><header><strong>Possibilities</strong><span>Original job-search specimen</span></header><section class="hero"><div class="hero-inner"><h1>Find your next possibility.</h1><form novalidate><div><label for="query">Role or city</label><input id="query" type="search" placeholder="Try designer or Melbourne" aria-describedby="error help"></div><button class="search" type="submit">Search jobs</button><button class="clear" type="button" id="clear">Clear search</button></form><div id="error" class="error" role="alert"></div><p id="help" class="help">Search three original sample roles. These are not live vacancies.</p></div></section><main><div class="results-head"><div><h2 id="count">3 sample results</h2><div class="applied" id="applied">Showing all sample roles</div></div></div><div id="results"></div><p class="boundary">Independent HTML interpretation of Braid’s search composition and responsive guidance. Original content and application palette; no SEEK data, account or application service is connected.</p></main><script>const jobs=[{title:'Product designer',city:'Melbourne',company:'North Studio',type:'Full time',mode:'Hybrid',initial:'NS',color:'',description:'Shape useful experiences with a small multidisciplinary product team.'},{title:'Design systems engineer',city:'Sydney',company:'Harbour Works',type:'Full time',mode:'Flexible',initial:'HW',color:'blue',description:'Build accessible components and improve the way teams deliver interfaces.'},{title:'UX researcher',city:'Melbourne',company:'Fern Collective',type:'Contract',mode:'On site',initial:'FC',color:'green',description:'Turn thoughtful field research into clear product opportunities.'}];const input=document.querySelector('#query'),error=document.querySelector('#error');let applied='';function render(){let matches=jobs.filter(j=>(j.title+' '+j.city).toLowerCase().includes(applied.toLowerCase()));document.querySelector('#count').textContent=matches.length+' sample '+(matches.length===1?'result':'results');document.querySelector('#applied').textContent=applied?'Applied search: '+applied:'Showing all sample roles';document.querySelector('#results').innerHTML=matches.length?matches.map(j=>`<article><div><h2>${j.title}</h2><div class="company">${j.company} · ${j.city}</div><div class="meta"><span>${j.type}</span><span>${j.mode}</span><span>Sample listing</span></div><p>${j.description}</p></div><div class="monogram ${j.color}" aria-hidden="true">${j.initial}</div></article>`).join(''):'<div class="notice">No sample roles match. Try another role or city, or clear your search.</div>'}document.querySelector('form').onsubmit=e=>{e.preventDefault();if(!input.value.trim()){error.textContent='Enter a role or city.';input.setAttribute('aria-invalid','true');input.focus();return}error.textContent='';input.removeAttribute('aria-invalid');applied=input.value.trim();render()};input.oninput=()=>{error.textContent='';input.removeAttribute('aria-invalid')};document.querySelector('#clear').onclick=()=>{input.value='';applied='';error.textContent='';input.removeAttribute('aria-invalid');render();input.focus()};render();</script></html>
```

代码参考

- 搜索范围仅包括示例中虚构的职位。使用原生 Braid 入口需要配置样式提取构建流程，并选择 seekJobs 主题。

### 草稿查询、已应用的搜索和明确的恢复方式

受控 TextField 用于验证本地查询，Actions 用于组合两种不同样式的按钮，而 Card/Stack/Heading/Text 则用于呈现原创搜索结果。

```
// Entry module in an existing sku application:
// npm install braid-design-system
import 'braid-design-system/reset'; // Keep this first.
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import seekJobsTheme from 'braid-design-system/themes/seekJobs';
import {BraidProvider,Box,Stack,Heading,Text,TextField,Button,Actions,Card} from 'braid-design-system';
const jobs=[{id:1,title:'Product designer',city:'Melbourne'},{id:2,title:'Design systems engineer',city:'Sydney'},{id:3,title:'UX researcher',city:'Melbourne'}];
function JobSearch(){
 const [draft,setDraft]=useState(''),[query,setQuery]=useState(''),[error,setError]=useState('');
 const results=jobs.filter(j=>(j.title+' '+j.city).toLowerCase().includes(query.toLowerCase()));
 function search(){if(!draft.trim()){setError('Enter a role or city.');return;}setError('');setQuery(draft.trim());}
 function clear(){setDraft('');setQuery('');setError('');}
 return <Box component="main" padding={{mobile:'medium',tablet:'xlarge'}}>
  <Stack space="large">
   <Heading level="2">Find your next possibility</Heading>
   <TextField id="job-query" label="Role or city" value={draft}
     onChange={event=>{setDraft(event.target.value);setError('');}}
     onClear={()=>setDraft('')} clearLabel="Clear role or city"
     tone={error?'critical':'neutral'} message={error||'Search three original sample roles.'}/>
   <Actions><Button tone="brandAccent" variant="solid" onClick={search}>Search jobs</Button>
    <Button variant="ghost" onClick={clear}>Clear search</Button></Actions>
   <Text>{results.length} sample results</Text>
   {results.map(job=><Card key={job.id}><Stack space="small"><Heading level="3">{job.title}</Heading><Text tone="secondary">{job.city}</Text></Stack></Card>)}
   {!results.length&&<Text>No sample roles match. Try a different title or city.</Text>}
   <Text size="small" tone="secondary">These are sample listings, not live vacancies.</Text>
  </Stack>
 </Box>;
}
createRoot(document.getElementById('root')).render(<BraidProvider theme={seekJobsTheme}><JobSearch/></BraidProvider>);
```

代码参考

- onChange 接收的是输入事件，而不是原始字符串。

- 查询为空时，Search 仍可用，并会提示用户输入内容。

- 清除搜索会同时重置草稿文本和已应用的结果。

## SEEK Braid 设计系统 Agent 配置

### 实现起点

这是适用于现有 sku 构建流程的完整应用入口，官方配置可直接支持该流程。自定义打包工具需要集成 Vanilla Extract。必须将重置样式的导入保留在第一位。离线预览不声称能够原生编译软件包。

```
// Entry module in an existing sku application:
// npm install braid-design-system
import 'braid-design-system/reset'; // Keep this first.
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import seekJobsTheme from 'braid-design-system/themes/seekJobs';
import {BraidProvider,Box,Stack,Heading,Text,TextField,Button,Actions,Card} from 'braid-design-system';
const jobs=[{id:1,title:'Product designer',city:'Melbourne'},{id:2,title:'Design systems engineer',city:'Sydney'},{id:3,title:'UX researcher',city:'Melbourne'}];
function JobSearch(){
 const [draft,setDraft]=useState(''),[query,setQuery]=useState(''),[error,setError]=useState('');
 const results=jobs.filter(j=>(j.title+' '+j.city).toLowerCase().includes(query.toLowerCase()));
 function search(){if(!draft.trim()){setError('Enter a role or city.');return;}setError('');setQuery(draft.trim());}
 function clear(){setDraft('');setQuery('');setError('');}
 return <Box component="main" padding={{mobile:'medium',tablet:'xlarge'}}>
  <Stack space="large">
   <Heading level="2">Find your next possibility</Heading>
   <TextField id="job-query" label="Role or city" value={draft}
     onChange={event=>{setDraft(event.target.value);setError('');}}
     onClear={()=>setDraft('')} clearLabel="Clear role or city"
     tone={error?'critical':'neutral'} message={error||'Search three original sample roles.'}/>
   <Actions><Button tone="brandAccent" variant="solid" onClick={search}>Search jobs</Button>
    <Button variant="ghost" onClick={clear}>Clear search</Button></Actions>
   <Text>{results.length} sample results</Text>
   {results.map(job=><Card key={job.id}><Stack space="small"><Heading level="3">{job.title}</Heading><Text tone="secondary">{job.city}</Text></Stack></Card>)}
   {!results.length&&<Text>No sample roles match. Try a different title or city.</Text>}
   <Text size="small" tone="secondary">These are sample listings, not live vacancies.</Text>
  </Stack>
 </Box>;
}
createRoot(document.getElementById('root')).render(<BraidProvider theme={seekJobsTheme}><JobSearch/></BraidProvider>);
```

### 适用于你项目的提示词

```
使用 seekJobs 主题组合 Braid 搜索界面，先导入重置样式，并通过 TextField 事件管理状态，再使用 Actions。单个主搜索按钮采用明确的 brandAccent 实心样式，重置按钮采用中性幽灵样式。允许提交空搜索并说明错误；不要禁用普通 Button 来隐藏验证提示。
```

## SEEK Braid 设计系统来源与适用范围

独立的 OpenDesign 参考示例。职位列表为原创内容，不包含实时职位空缺，也不支持提交申请。命名的 Braid 变量会根据选定主题解析。

- 配置与构建 重置顺序、sku 与 Vanilla Extract。

- BraidProvider 主题与嵌入式 body 的行为。

- 变量 作用域限定的 CSS 表达式和角色名称。

- 断点 共享的响应式断点。

- Box 语义元素与响应式实用属性。

- 文本 字号、语义和上下文色调。

- Button 色调、变体和禁用状态的行为。

- TextField 标签、错误提示和清除操作。

- TextField 属性 精确的回调类型和受控值类型。

## SEEK Braid 设计系统相关资源

### Segment Evergreen

一份 Evergreen 参考示例，包含实际主题取值、受控标签输入、实时规则匹配、空状态恢复路径和原生审核对话框。

### Semi Design

创建顺序式工作区设置，采用 Semi 推荐的基础 Steps、受控 Input 和 Switch、真实主题令牌，并明确选择使用 React 18 还是 React 19 程序包。

### Semrush Intergalactic

一份星际主题指南，包含当前语义令牌和图表令牌、原生筛选控件、固定比例对比、选中项详情，以及完整的可复现测试样例。


- [实现参考](https://seek-oss.github.io/braid-design-system/components/Button/)
- [来源](https://seek-oss.github.io/braid-design-system/css/breakpoints/)
- [来源](https://seek-oss.github.io/braid-design-system/css/vars/)
- [来源](https://seek-oss.github.io/braid-design-system/components/Box/)
- [来源](https://seek-oss.github.io/braid-design-system/components/TextField/)
- [来源](https://seek-oss.github.io/braid-design-system/components/Button/)
- [来源](https://seek-oss.github.io/braid-design-system/components/Text/)
- [阅读配套规范](https://seek-oss.github.io/braid-design-system/components/BraidProvider/)
- [阅读配套规范](https://seek-oss.github.io/braid-design-system/css/breakpoints/)
- [阅读配套规范](https://seek-oss.github.io/braid-design-system/components/Text/)
- [阅读配套规范](https://seek-oss.github.io/braid-design-system/components/Button/)
- [阅读配套规范](https://seek-oss.github.io/braid-design-system/components/TextField/)
- [阅读配套规范](https://seek-oss.github.io/braid-design-system/components/TextField/props/)
- [阅读配套规范](https://github.com/seek-oss/braid-design-system)
- [代码参考](https://seek-oss.github.io/braid-design-system/components/Button/)
- [代码参考](https://seek-oss.github.io/braid-design-system/components/TextField/props/)
- [配置与构建 重置顺序、sku 与 Vanilla Extract。](https://github.com/seek-oss/braid-design-system)
- [BraidProvider 主题与嵌入式 body 的行为。](https://seek-oss.github.io/braid-design-system/components/BraidProvider/)
- [变量 作用域限定的 CSS 表达式和角色名称。](https://seek-oss.github.io/braid-design-system/css/vars/)
- [断点 共享的响应式断点。](https://seek-oss.github.io/braid-design-system/css/breakpoints/)
- [Box 语义元素与响应式实用属性。](https://seek-oss.github.io/braid-design-system/components/Box/)
- [文本 字号、语义和上下文色调。](https://seek-oss.github.io/braid-design-system/components/Text/)
- [Button 色调、变体和禁用状态的行为。](https://seek-oss.github.io/braid-design-system/components/Button/)
- [TextField 标签、错误提示和清除操作。](https://seek-oss.github.io/braid-design-system/components/TextField/)
- [TextField 属性 精确的回调类型和受控值类型。](https://seek-oss.github.io/braid-design-system/components/TextField/props/)
