Изучите Braid на примере оригинального сценария поиска работы: переменные в области действия темы, четыре реальные точки останова, контекстный текст, разные тона кнопок и управляемое поле, которое объясняет ошибку проверки вместо блокировки действия.
Исходная автономная интерпретация композиции поиска, иерархии и рекомендаций по контрольным точкам Braid HTML; без актуальных данных SEEK и среды выполнения Braid. Цвета предварительного просмотра и физические отступы выбраны для приложения. · Справочник по реализации
02
SEEK Braid Справочник по дизайн-системе
Актуальные ссылки на компоненты Braid и CSS. Именованные размеры определяются выбранной темой; непроверенные значения в пикселях и выдуманные имена переменных CSS здесь не используются. В нативном примере явно выбрана тема seekJobs.
Дизайн-система SEEK Braid: выбранная тема задаёт визуальный контракт
Провайдер, сброс стилей и сгенерированные переменные работают вместе
Braid поддерживает несколько тем SEEK Group. Переменная API содержит выражения CSS с заданной областью действия, поэтому такие имена, как vars.space.medium, остаются стабильными ссылками, а идентификатор сгенерированного пользовательского свойства не нужно воспроизводить вручную. В примере через BraidProvider выбрана тема seekJobs.
Импорт сброса стилей должен предшествовать остальным стилям Braid. Во встроенном приложении свойство styleBody={false} позволяет не менять фон и отступы body родительской страницы. Эта настройка не отменяет необходимости в контексте темы.
Дизайн-система SEEK Braid: адаптивные значения используют именованные интервалы темы
Используйте все четыре фактических условия контрольных точек
Общие пороговые значения: мобильные устройства — от нуля, планшеты — от 740px, настольные компьютеры — от 992px, широкие экраны — от 1200px. В нативном примере отступ меняется на пороге планшетной версии с помощью объекта адаптивных свойств. Для этого изменения не дублируется медиазапрос CSS.
Средний интервал темы не описывается здесь предположительным значением в пикселях. В первую очередь используйте Box и Stack для отступов. vars — это низкоуровневый способ обойти ограничения, если макет нельзя выразить с помощью этих компонентов; поскольку значения — это выражения CSS, для умножения используется calc, а не числовая арифметика JavaScript.
Дизайн-система SEEK Braid: роли текста учитывают цветовой контекст
Выбирайте иерархию и семантику независимо друг от друга
Text предлагает именованные размеры и начертания, а Heading задаёт иерархию заголовков. Для города в карточке вакансии можно использовать вторичный тон, но заголовок должен оставаться достаточно заметным, чтобы выделять результат. Если содержимое представляет собой абзац, Text можно преобразовать в элемент абзаца с помощью component="p" — вместо того, чтобы выбирать элемент HTML только из-за его стандартного внешнего вида.
Braid корректирует цвета текста для тёмного фонового контекста. Если используется исходное изображение или пользовательский фон, связь с ним можно обозначить с помощью контекста Box customDark. Нельзя считать, что div с заданным вручную цветом обеспечивает такое же поведение с учётом контекста.
Дизайн-система SEEK Braid: tone задаёт смысл, а variant — значимость
Оставьте фирменный акцент для действия поиска
В примере для кнопки Search jobs явно заданы сплошной вариант и тон brandAccent. Очистка поиска — менее заметное действие с вариантом ghost. formAccent подходит для повторяющихся действий в формах; critical предназначен для разрушительных последствий, поэтому его не следует использовать для привлечения внимания к обычным элементам управления.
В Braid есть нюанс: по умолчанию нейтральная кнопка использует вариант ghost, если не задано иное, а указание tone автоматически задаёт неявный вариант solid. Для ключевого действия укажите оба свойства, чтобы его иерархия была очевидной. Actions обычно располагает элементы вертикально на мобильных устройствах и в одну строку на широких экранах.
Дизайн-система SEEK Braid: действие с ошибкой лучше недоступной кнопки
Соблюдайте контракт управляемого поля
Колбэк onChange компонента TextField получает событие React ввода. В примере считывается event.target.value, текст сохраняется в состоянии черновика, а применяемый поисковый запрос меняется только после нажатия Search. Также передаётся колбэк очистки, поскольку элемент управления не может самостоятельно сбросить состояние приложения.
Свойство message объясняет ошибку пустого запроса, а тон critical задаёт её визуальное состояние. description предназначен для постоянного контекста. Обычная кнопка Braid Button не поддерживает состояние disabled; действие остаётся доступным, чтобы пользователь мог понять, как продолжить. Кроме того, в автономном предпросмотре фокус перемещается на поле с ошибкой.
Храните редактируемый текст в состоянии черновика запроса.
При нажатии Search требуйте непустой запрос после удаления пробелов по краям.
При сбое выводите понятное критическое сообщение.
Применяйте запрос в случае успеха и явно обозначайте отсутствие результатов.
Дизайн-система SEEK Braid: пример использует только исходные данные
Локальные результаты не означают наличие актуальных вакансий
В предпросмотре представлены три вымышленные вакансии с данными о должности, городе и формате работы. При поиске названия должностей и городов сравниваются без учёта регистра. Данные не загружаются из актуальных списков вакансий SEEK, а результаты помечены как примеры.
Раздельное хранение чернового текста и применённых результатов делает взаимодействие наглядным: при редактировании должности текущие результаты не меняются без нажатия Search. Очистка поиска сбрасывает оба значения. Если совпадений нет, список результатов сообщает об этом, а элементы управления поиском остаются доступными.
После применения запроса показывайте количество результатов.
Во время редактирования сохраняйте понятную формулировку последнего применённого запроса.
Не добавляйте фиктивную отправку формы Apply для примеров вакансий.
Официальная настройка оптимизирована для sku. Для стилей Braid на Vanilla Extract требуется интеграция со сборкой при использовании собственного сборщика, а сброс стилей и выбранная тема должны подключаться к приложению в указанном порядке. Приведённый код — полноценная точка входа для существующего совместимого проекта sku, а не утверждение, что Braid можно запустить с помощью случайного тега script.
Braid выполняет проверки в режиме разработки и выдаёт предупреждения в зависимости от среды. В официальных рекомендациях по сборке предлагается удалять проверки и подменять сведения о среде на этапе production-сборки. Учитывайте это в процессе реализации; автономный пример HTML на странице не зависит от такой сборки пакетов.
Сохраните весь документ как index.html и откройте его в браузере. Самостоятельная автономная HTML интерпретация поисковой композиции Braid, иерархии и рекомендаций по контрольным точкам; без актуальных данных SEEK и среды выполнения Braid. Цвета предпросмотра и фактические отступы выбраны для приложения.
html
<!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 отображают исходные результаты.
jsx
// 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 остаётся доступной, а интерфейс подсказывает, что нужно ввести.
Очистка поиска сбрасывает и черновой текст, и применённые результаты.
04
SEEK Braid Настройка агента дизайн-системы
Отправная точка для реализации
Полноценная точка входа приложения для существующей сборки sku, которая поддерживается официальной настройкой напрямую. Для собственных сборщиков требуется интеграция Vanilla Extract. Импорт сброса стилей должен оставаться первым. Автономный предпросмотр не заявляет о возможности скомпилировать нативные пакеты.
jsx
// 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>);
Запрос для вашего проекта
Промпт для AI-агента
Составьте поисковую форму Braid с темой seekJobs, импортируйте сброс стилей первым, используйте состояние события TextField и компонент Actions. Для основной кнопки поиска явно укажите brandAccent и solid, а для сброса используйте нейтральный ghost. Разрешайте отправку пустого запроса и объясняйте ошибку; не отключайте обычную кнопку, чтобы скрыть ошибку проверки.
05
SEEK Braid Источники и область применения дизайн-системы
Независимый справочник OpenDesign. Исходные примеры вакансий, без актуальных вакансий и отправки заявок. Именованные переменные Braid разрешаются через выбранную тему.