Создайте пошаговую настройку рабочей среды с базовыми элементами Steps, рекомендованными Semi, управляемыми компонентами Input и Switch, реальными токенами темы и явным выбором пакета React 18 или React 19.
Офлайн-интерпретация HTML шкал темы Semi и поведения Steps/Input/Switch. Отдельный пример с нативным React. · Справочник по реализации
02
Справочник по дизайн-системе Semi Design
Официальная документация Semi и снимок SCSS темы по умолчанию. Имена $ — константы Sass, используемые на этапе компиляции; имена --semi-* — переменные CSS времени выполнения. Данные рабочего процесса приложения созданы специально для примера.
Дизайн-система Semi Design: выберите пакет для используемого мажорного выпуска React
Суффикс меняет способ интеграции
В актуальном кратком руководстве Semi пакет React 19 отделён от пакета, который используется в более ранних версиях React. В этом примере явно выбраны React 18 и @douyinfe/semi-ui. Для перехода на React 19 необходимо выбрать зависимость и импорты @douyinfe/semi-ui-19, как указано в документации.
Поддерживаемые сборщики загружают связанные CSS из компонентов JavaScript. Для изменений на этапе компиляции — например, пользовательского префикса, компиляции темы или слоёв CSS — нужны отдельные инструменты и настройки. Не следует на основании простого примера импорта утверждать, что любая настройка темы работает без конфигурации.
Дизайн-система Semi Design: именованные шкалы Sass задают конкретную плотность
Используйте опубликованные высоты элементов управления: 24, 32 и 40px
Три константы высоты элементов управления Semi — 24, 32 и 40px. Именованные отступы охватывают диапазон от 2 до 40px с неравномерным шагом. Для стандартного поля в мастере можно задать отступ 12px до пояснения и 24px до следующего раздела, не вводя новую шкалу отступов.
Это константы Sass, а не автоматически доступные переменные времени выполнения. В примере используются соответствующие им размеры на странице CSS. Это важно учитывать, если разработчик хочет менять оформление макета во время выполнения, а не пересобирать таблицу стилей.
Дизайн-система Semi Design: используйте реальные сочетания размера и высоты строки
Основной текст и заголовки имеют разный ритм
Обычный миксин сочетает шрифт размером 14px с высотой строки 20px, а малый — размер 12px с высотой строки 16px. Заголовок уровня 3 — 24/32, уровня 1 — 32/44. Для краткого названия мастера подойдёт первый вариант, а второй лучше оставить для более выраженной иерархии страницы.
В исходном списке шрифтов первым указан Inter, за ним следуют системные шрифты и шрифты для китайского, японского и корейского письма. В офлайн-предпросмотре используется доступный системный набор шрифтов — он не утверждает, что загружен конкретный шрифт. Формулируйте названия шагов кратко, чтобы они сохраняли смысл при переносе панели шагов на узком экране.
Дизайн-система Semi Design: роли темы и каналы палитры — разные понятия
Используйте готовые значения ролей в приложении CSS
Основная роль использует переменную канала палитры, обёрнутую в rgba. Переменная --semi-color-primary подходит для обычного свойства цвета; необработанный список каналов --semi-blue-5 сам по себе не является полным цветом CSS. В светлой и тёмной палитрах значения этих каналов различаются.
В ролях текста также используется прозрачность. Для вторичного текста не следует произвольно выбирать более светлый шестнадцатеричный цвет, а цвет отключённого текста не подходит для важной справки. Сообщение о завершении в мастере нейтральное: подготовка конфигурации не создаёт действующую учётную запись.
Дизайн-система Semi Design: Basic Steps показывает прогресс, а не даёт разрешение пропустить проверку
Правила переходов определяет приложение
Для простой панели шагов Semi рекомендует type="basic". Отсчёт current начинается с нуля, а текущему шагу можно назначить статус process, error или другой поддерживаемый статус. Более старое оформление по умолчанию в документации помечено как устаревшее.
В примере переход между шагами выполняется намеренно с помощью кнопок «Продолжить» и «Назад». Переход по нажатию на каждый шаг не вызывает setCurrent: иначе пользователь смог бы перейти к проверке с пустым именем. Описанное отдельно оформление nav не является интерактивным, и его не следует принимать за навигацию мастера.
Проверьте имя, прежде чем переходить с первого шага.
Сохраняйте выбранное значение настройки еженедельной рассылки при возврате к предыдущим шагам.
Покажите все параметры на экране проверки.
Подготовьте локальную конфигурацию, не утверждая, что учётная запись или подписка уже созданы.
Дизайн-система Semi Design: визуальная проверка не подтверждает корректность значения
Правильно используйте колбэк, который первым принимает значение
Компонент Input из Semi передаёт в onChange сначала значение, а затем событие. Поэтому в примере можно напрямую передать setName. Параметр validateStatus меняет только внешний вид; проверка имени на пустое значение — логика приложения, и её результат нужно объяснить пользователю.
Для текста, запускающего динамические запросы, колбэки можно отложить до подтверждения композиции через IME. Поле имени рабочего пространства не выполняет динамические запросы, поэтому в примере не используется это необязательное поведение и не создаётся впечатление, что оно требуется всегда.
Дизайн-система Semi Design: назначение настройки понятно и без подписи рядом с переключателем
Храните состояние в родительском компоненте
Switch использует checked и колбэк onChange, первым аргументом которого является логическое значение. Подпись должна объяснять настройку, например «Еженедельная сводка», а окружающий текст — смысл параметра. Длинные подписи для включённого и выключенного состояний размещайте вне небольшого элемента управления: компактные переключатели не поддерживают такие внутренние подписи.
Дизайн-система Semi Design: тип кнопки и её тема отвечают на разные вопросы
Семантическая роль и визуальное оформление
В Button из Semi параметр type задаёт роль, например primary или danger. Параметр theme задаёт визуальное оформление: light, solid, borderless или outline. В примере действие «Продолжить» оформлено как solid primary, а кнопка «Назад» — сдержаннее; danger не используется просто для того, чтобы сделать кнопку заметнее.
В офлайн-примере при смене шага фокус перемещается на заголовок нового раздела, а при ошибке проверки возвращается к полю с неверным значением. Мобильную версию и последовательность перехода с клавиатуры проверяют отдельно от примера с нативным React, сверенного с исходным кодом.
Сохраните документ целиком как index.html и откройте его в браузере. Офлайн-интерпретация HTML шкал темы Semi и поведения Steps/Input/Switch. Отдельный пример с нативным React.
html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Semi workspace setup interpretation</title><style>
*{box-sizing:border-box}body{margin:0;background:#f5f6f8;color:#1c1f23;font:14px/20px Inter,system-ui,sans-serif}button,input{font:inherit}button{cursor:pointer;min-height:32px;border:0;border-radius:3px;padding:6px 16px;background:rgba(46,50,56,.05);color:inherit}button.primary{background:#0064fa;color:white}button.primary:hover{background:#0062d6}button:focus-visible,input:focus-visible{outline:2px solid #0064fa;outline-offset:3px}header{padding:20px 32px;border-bottom:1px solid rgba(28,31,35,.08);background:white;display:flex;justify-content:space-between;gap:16px}header strong{font-size:16px}header span,.muted{color:#63656a}main{max-width:950px;margin:32px auto;padding:0 24px}h1{font-size:24px;line-height:32px;font-weight:600;margin:0 0 8px}h2{font-size:20px;line-height:28px;font-weight:600;margin:0 0 12px}p{margin:0 0 16px}.card{background:white;border:1px solid rgba(28,31,35,.08);border-radius:12px;overflow:hidden;margin-top:24px}.steps{padding:24px;display:flex;list-style:none;margin:0;border-bottom:1px solid rgba(28,31,35,.08);gap:12px}.steps li{flex:1;display:flex;align-items:center;gap:8px;color:#63656a;font-size:12px}.steps b{height:24px;width:24px;border-radius:50%;display:grid;place-items:center;background:#eee;flex-shrink:0}.steps [aria-current]{color:#0064fa}.steps [aria-current] b{background:#0064fa;color:white}.steps .done b{background:#eaf5ff;color:#0064fa}.workspace{display:grid;grid-template-columns:1fr 240px;min-height:300px}.panel{padding:32px}.illustration{background:#eaf5ff;display:flex;flex-direction:column;justify-content:center;padding:24px;gap:12px}.mini{background:white;box-shadow:0 6px 20px #0064fa12;border-radius:6px;padding:16px;transform:rotate(-3deg)}.mini i{display:block;height:8px;background:#eaf5ff;width:80%;margin:8px 0;border-radius:3px}.mini i:first-child{background:#0064fa;width:36%}.mini i:nth-child(3){width:55%}.mini:last-child{transform:rotate(4deg);margin-left:20px}.mini span{font-size:12px;color:#63656a}.form-label{display:block;font-weight:600;margin:20px 0 8px}input[type=text]{height:32px;background:rgba(46,50,56,.05);border:1px solid transparent;border-radius:3px;padding:5px 12px;width:100%}input[aria-invalid=true]{border-color:#d52515}.error{color:#b21b13;min-height:20px;font-size:12px;margin:8px 0}.preference{border:1px solid #eee;border-radius:6px;padding:16px;display:flex;align-items:center;justify-content:space-between;gap:20px}.preference p{margin:4px 0 0;font-size:12px}.toggle{appearance:none;width:40px;height:24px;border-radius:999px;background:#bbb;position:relative;cursor:pointer;flex-shrink:0}.toggle:checked{background:#0064fa}.toggle:before{content:'';position:absolute;left:3px;top:3px;background:white;border-radius:50%;width:18px;height:18px}.toggle:checked:before{left:19px}footer{display:flex;justify-content:space-between;padding:20px 32px;border-top:1px solid rgba(28,31,35,.08)}dl{margin:20px 0}dt{color:#63656a;font-size:12px}dd{margin:4px 0 20px;font-size:16px;font-weight:600;overflow-wrap:anywhere}#result{margin-top:16px;border-radius:6px;background:#eaf5ff;padding:16px}#result:empty{display:none}.boundary{font-size:12px;margin-top:20px;color:#63656a}h2:focus{outline:none}@media(max-width:600px){header{padding:16px}header span{display:none}main{margin:24px auto;padding:0 16px}.workspace{grid-template-columns:1fr}.illustration{display:none}.steps{padding:16px;gap:8px}.steps li{flex-direction:column;align-items:flex-start;gap:4px}.panel{padding:24px 20px}footer{padding:16px 20px;gap:12px}footer button{padding:6px 12px}}
</style><header><strong>◒ Workspace</strong><span>Configuration studio</span></header><main><h1>Make room for your team</h1><p class="muted">Three steps to prepare a workspace configuration.</p><div class="card"><ol class="steps" aria-label="Setup progress"><li><b>1</b>Name workspace</li><li><b>2</b>Choose updates</li><li><b>3</b>Review settings</li></ol><div class="workspace"><section class="panel" id="panel"></section><aside class="illustration" aria-hidden="true"><div class="mini"><i></i><i></i><i></i><span>A place for shared ideas</span></div><div class="mini"><i></i><i></i><i></i><span>Updates on your terms</span></div></aside></div><footer><button id="previous">Previous</button><button class="primary" id="next">Continue</button></footer></div><div id="result" role="status"></div><p class="boundary">Independent HTML interpretation of Semi’s theme and components. This example stores a draft only in memory; it does not create an account.</p></main><script>
let step=0,name='',digest=true;const panel=document.querySelector('#panel'),next=document.querySelector('#next'),previous=document.querySelector('#previous'),result=document.querySelector('#result');function render(focus=false){document.querySelectorAll('.steps li').forEach((el,i)=>{el.className=i<step?'done':'';el.removeAttribute('aria-current');if(i===step)el.setAttribute('aria-current','step')});previous.style.visibility=step?'visible':'hidden';next.textContent=step===2?'Prepare configuration':'Continue';if(step===0){panel.innerHTML='<h2 tabindex="-1">Name your workspace</h2><p class="muted">Choose a name your team will recognize.</p><label class="form-label" for="name">Workspace name</label><input id="name" type="text" placeholder="e.g. Studio North" autocomplete="organization" aria-describedby="help error"><p id="error" class="error" role="alert"></p><p id="help" class="muted">You can revisit this step before preparing the configuration.</p>';let input=document.querySelector('#name');input.value=name;input.oninput=()=>{name=input.value;input.removeAttribute('aria-invalid');document.querySelector('#error').textContent='';result.textContent=''};input.onkeydown=e=>{if(e.key==='Enter')next.click()}}else if(step===1){panel.innerHTML='<h2 tabindex="-1">Choose your updates</h2><p class="muted">Keep the weekly digest in your configuration, or switch it off.</p><label class="preference"><span><strong>Weekly digest</strong><p class="muted">A weekly summary of workspace activity.</p></span><input class="toggle" type="checkbox" role="switch" aria-label="Weekly digest" id="digest"></label>';let input=document.querySelector('#digest');input.checked=digest;input.onchange=()=>{digest=input.checked;result.textContent=''}}else{panel.innerHTML='<h2 tabindex="-1">Review settings</h2><p class="muted">Check the draft before preparing it.</p><dl><dt>Workspace name</dt><dd id="review-name"></dd><dt>Weekly digest</dt><dd id="review-digest"></dd></dl>';document.querySelector('#review-name').textContent=name.trim();document.querySelector('#review-digest').textContent=digest?'Enabled':'Disabled'}if(focus)panel.querySelector('h2').focus()}
next.onclick=()=>{if(step===0&&!name.trim()){document.querySelector('#error').textContent='Enter a workspace name.';let input=document.querySelector('#name');input.setAttribute('aria-invalid','true');input.focus();return}if(step<2){step++;render(true)}else result.textContent='Configuration prepared locally: '+name.trim()+' · Weekly digest '+(digest?'enabled':'disabled')+'. No account created.'};previous.onclick=()=>{step=Math.max(0,step-1);result.textContent='';render(true)};render();
</script></html>
Перед переходом к следующему шагу кнопка «Продолжить» проверяет имя рабочего пространства. В этом документе интерпретируется поведение шагов; в отдельной записи React указана граница между пакетами React 18 и 19.
Мастер настройки с проверкой и тремя шагами
Basic Steps показывает текущий шаг; Input и Switch сохраняют значения при переходе между страницами. Кнопка «Продолжить» проверяет имя, а последнее действие только подготавливает локальную конфигурацию.
jsx
// React 18 example. React 19 uses @douyinfe/semi-ui-19 instead.
// npm install react@18 react-dom@18 @douyinfe/semi-ui
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import {Steps,Input,Switch,Button} from '@douyinfe/semi-ui';
function WorkspaceSetup(){
const [current,setCurrent]=useState(0),[name,setName]=useState('');
const [digest,setDigest]=useState(true),[error,setError]=useState('');
const [prepared,setPrepared]=useState(false);
function next(){
if(current===0&&!name.trim()){setError('Enter a workspace name.');return;}
setError('');setCurrent(n=>Math.min(2,n+1));
}
return <main style={{maxWidth:760,margin:'auto',padding:24,color:'var(--semi-color-text-0)'}}>
<h1>Workspace setup</h1>
<Steps type="basic" current={current} status={error?'error':'process'}>
<Steps.Step title="Name workspace"/>
<Steps.Step title="Choose updates"/>
<Steps.Step title="Review settings"/>
</Steps>
<section style={{padding:'24px 0'}}>
{current===0&&<><label htmlFor="workspace-name">Workspace name</label>
<Input id="workspace-name" value={name} onChange={setName}
validateStatus={error?'error':'default'} aria-invalid={!!error} aria-describedby="error" />
<p id="error" role="alert">{error}</p></>}
{current===1&&<><h2>Weekly digest</h2><p>Include a weekly activity summary in the local configuration.</p>
<Switch checked={digest} onChange={setDigest} aria-label="Weekly digest"/></>}
{current===2&&<><h2>Review your draft</h2><dl><dt>Workspace</dt><dd>{name}</dd>
<dt>Weekly digest</dt><dd>{digest?'Enabled':'Disabled'}</dd></dl>
<p>No workspace or notification subscription is created.</p></>}
</section>
{current>0&&<Button onClick={()=>{setCurrent(n=>n-1);setPrepared(false);}}>Previous</Button>}
{current<2 ? <Button theme="solid" type="primary" onClick={next}>Continue</Button> :
<Button theme="solid" type="primary" onClick={()=>setPrepared(true)}>Prepare configuration</Button>}
<p role="status">{prepared?'Configuration prepared locally. No account created.':''}</p>
</main>;
}
createRoot(document.getElementById('root')).render(<WorkspaceSetup />);
В примере для React 18 намеренно устанавливается @douyinfe/semi-ui; для React 19 нужен пакет -19, указанный в кратком руководстве.
Компоненты JavaScript загружают связанные с ними CSS в поддерживаемых сборщиках; стандартная настройка не требует выдуманного шага с подключением глобальной таблицы стилей.
Встроенный пример HTML явно задаёт перемещение фокуса; реализуйте аналогичное поведение при работе с нативными компонентами в продукте.
04
Настройка агента дизайн-системы Semi Design
Отправная точка для реализации
Выберите одну ветку зависимостей. В примере используется React 18. В актуальном кратком руководстве сказано, что компоненты JavaScript загружают связанные с ними CSS в Vite/Webpack/Rspack; для компиляции темы нужны дополнительные инструменты.
bash
npm install react@18 react-dom@18 @douyinfe/semi-ui
# For a React 19 application instead:
# npm install react@19 react-dom@19 @douyinfe/semi-ui-19
Запрос для вашего проекта
Промпт для AI-агента
Используйте базовый Steps из Semi с управляемыми Input и Switch. Версия пакета React должна соответствовать установленному мажорному выпуску React. Проверяйте данные перед переходом, сохраняйте их при нажатии «Назад» и показывайте итоговую локальную конфигурацию, не изображая несуществующее создание учётной записи.
05
Источники и область применения дизайн-системы Semi Design
Независимый справочник OpenDesign. Оригинальный пример рабочего пространства; учетная запись не создается, подписка на уведомления не оформляется.