Перейти к содержимому
Поиск
Разработка

Cosmic UI: компоненты React, темы и практические примеры

Разбираем Cosmic UI на практических сценариях: настраиваем тему, показываем состояния кнопки, открываем диалог и проверяем клавиатуру. Площадка с примерами и пояснениями к коду.

Александр Некрасов
Cosmic UI для React: оформление, управление и состояния компонентов

У интерфейса космического терминала есть узнаваемый язык: угловатые рамки, светящиеся акценты, технические подписи и панели с чётким ритмом. Но посетитель всё равно хочет выполнить обычную задачу — выбрать режим, заполнить поле, подтвердить действие. Разберём Cosmic UI с этой точки зрения: как получить выразительный React-интерфейс и сохранить понятное поведение его элементов.

Схема трёх слоёв Cosmic UI: оформление, управление мышью и клавиатурой, состояния компонента.
Схема принципаКрасивый компонент должен оставаться понятным

Декоративная рамка задаёт характер, действия остаются привычными, а логика состояний управляет открытием, выбором и фокусом.

Увеличить изображение ⤢

Что такое Cosmic UI и для каких задач он подходит

Cosmic UI — набор компонентов с оформлением в духе научной фантастики. На официальном сайте есть отдельные примеры для React и Vue; здесь рассматриваем React. Кнопки, поля, диалоги и вкладки используют общий визуальный язык. Его характерная часть — Frame, SVG-декорация с несколькими контурами, срезанными углами и настраиваемыми цветами.

Удобная область применения — небольшая панель управления, демонстрация продукта, игровой кабинет или необычная страница проекта. Сначала выделите несколько повторяемых элементов: основное действие, переключение разделов, форму настройки. Затем дайте им одинаковые правила цвета, отступов и подписей. Такой подход помогает построить цельный экран, а не коллекцию эффектных деталей.

Если на странице много текста, оставьте ему спокойную область и обычный читаемый шрифт. Яркую рамку лучше поставить вокруг важного блока, чем вокруг каждого предложения. Цвет тоже должен иметь назначение: основной акцент ведёт к следующему действию, предупреждение объясняет риск, подтверждение показывает результат. Вид интерфейса можно сделать необычным, сохранив привычную логику.

Компоненты добавляются в исходники проекта. Это позволяет изучать их разметку и менять оболочку под свою задачу. При этом установка одной кнопки не подключает готовую бизнес-логику: отправку формы, проверку доступа и обработку ответа сервера разработчик задаёт отдельно.

Учебная площадка: смотрите на сценарий, а не только на форму

Площадка ниже предназначена для проверки оформления и поведения. Поменяйте параметры примера, попробуйте действия мышью и клавиатурой, сравните состояния элементов. Тексты и настройки здесь нужны для демонстрации интерфейса; они не означают отправку заявки, запуск оборудования или сохранение данных в вашем проекте.

На площадке разбираем восемь групп: кнопки, поля, флажки и переключатели, вкладки, аккордеон, диалог, меню и уведомления. Палитра и сила свечения относятся к нашей оболочке примеров. Сначала выберите знакомый элемент, затем проверьте его в другом оформлении: поведение должно оставаться предсказуемым.

Интерфейс со своим характером

Попробуйте компоненты Cosmic UI

Выберите пример, измените акцент и проверьте кнопки, формы, вкладки и диалоги. Настройки остаются в вашем браузере.

Открыть площадку отдельно ↗

Отдельная вкладка удобна для просмотра компонентов и кода рядом.

Продолжите в своём проекте

Исходники, закреплённые зависимости и инструкция локального запуска.

Скачать пример проекта

Рабочая площадка Cosmic UI: настоящие кнопки с футуристичной рамкой и панель настройки оформления.
Наша площадкаКомпонент, его настройки и понятный результат

Скриншот нашей интерактивной площадки. Выберите компонент, измените палитру и попробуйте действие; затем скопируйте пример для своего React-проекта.

Увеличить изображение ⤢

  1. Начните с обычного состояния. Видно ли, какая кнопка главная? Понятно ли назначение поля без пояснения автора?
  2. Выполните действие. Дождитесь результата. Обратите внимание, остаётся ли интерфейс понятным в промежуточном состоянии.
  3. Повторите без мыши. Перейдите к элементу клавишей Tab, активируйте его и найдите способ вернуться назад.
  4. Измените условия. Выберите длинную подпись или узкий экран. Проверьте, что рамка, текст и зона нажатия продолжают работать вместе.

Хороший результат — не просто красивый первый кадр. Посетитель должен различать выбранный режим и наведение, понимать причину недоступного действия и видеть подтверждение после завершения операции. Если это теряется при смене цвета, сначала поправьте контраст и подписи, затем добавляйте свечение.

Подключение: проект, стили и CLI решают разные задачи

Для самостоятельного React-примера официальный маршрут предполагает проект с TypeScript, сборку Vite и Tailwind CSS. Tailwind создаёт используемые компонентами классы, CSS-переменные задают цвета, а CLI переносит нужные файлы и находит их зависимости. Эти части нужны вместе: файл кнопки без её рамки или без собранных стилей не даст ожидаемый результат.

В React-проекте, где уже настроены Tailwind 4 и алиас @, можно начать с таких команд. Дополнительно устанавливаем CSS-анимации. Версия CLI указана явно; серверный реестр компонентов при этом может обновляться независимо от неё.

npx @left4code/cosmic-ui-cli@0.1.0 init --framework react
npx @left4code/cosmic-ui-cli@0.1.0 add button dialog tabs
npm install tw-animate-css
npm run dev

init создаёт cosmic.json и файл цветовых токенов. При стандартном каталоге src/components это src/cosmic-ui.css. add записывает выбранные компоненты, связанные файлы и предлагает установить npm-зависимости. Например, диалог использует общие части для портала, присутствия на странице и рамки. Проверьте предложенный состав, затем откройте простой экран с одним элементом.

В конфигурации проекта понадобится алиас @ к src: он должен разрешаться и TypeScript, и Vite. Входной CSS должен подключать Tailwind и токены. Зависимости анимации и SVG-отрисовки тоже должны присутствовать, если их использует выбранный компонент. Точный порядок первоначальной настройки приведён в официальной инструкции подключения.

Темы: меняйте смысловые токены, а не каждый элемент отдельно

Токен — именованная переменная для повторяемого решения. --color-primary задаёт основной акцент, --color-primary-foreground — текст для этого акцента. Аналогичные пары есть для дополнительных, успешных и опасных действий. Рамки используют эти цвета через собственные переменные штриха и заливки, поэтому согласованная палитра затрагивает несколько компонентов сразу.

Ниже — небольшой собственный пример настройки. Он рассчитан на CSS-вход Tailwind 4 и уже созданный CLI-файл токенов. Класс cosmic-preview — наша область демонстрации; его нужно поставить на контейнер с примерами.

@import "tailwindcss";
@import "tw-animate-css";
@import "./cosmic-ui.css";

.cosmic-preview {
  --color-primary: #76d7ff;
  --color-primary-foreground: #f5fbff;
  --color-accent: #ffc48a;
  --color-accent-foreground: #fff8f0;
  --color-background: #102332;
  --color-foreground: #edf5fb;
  background: var(--color-background);
  color: var(--color-foreground);
}

.cosmic-preview button:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 4px;
}

Перед изменением палитры определите фон экрана и фон самого элемента. Полупрозрачная заливка смешивается с окружением: один и тот же цвет на светлой карточке и тёмной панели воспринимается по-разному. Поэтому проверяйте кнопку на настоящем фоне, включая наведение, выбранное состояние и недоступное действие.

Переменные контейнера наследуют его потомки. У диалога, который переносится через портал в document.body, другая ветка DOM. Если тема нужна всему приложению, задайте её на общем корне документа; если только отдельному виджету — предусмотрите передачу темы к его порталу. Иначе панель может быть бирюзовой, а открывшееся окно получит исходную палитру.

Не называйте изменение двух цветов полноценной дизайн-системой. Для последовательного результата нужны ещё размеры текста, отступы, состояния, правила использования и проверка контраста. Начните с одной пары «фон — текст», затем добавьте акценты и только после этого декоративные эффекты.

Кнопка: показывайте действие, ожидание и результат

У Button есть варианты default, accent, secondary, success и destructive. Форма задаётся отдельно: например, flat упрощает декорацию, а simple меняет контур. Выберите вариант по назначению действия. Подпись «Сохранить настройки» объясняет больше, чем «Активировать протокол», если речь идёт об обычном сохранении.

Для длительного действия заведите понятные состояния. В нашем примере это «готово к работе», «сохраняем», «получилось» и «ошибка». Функция saveProject передаётся извне: именно она выполняет реальную работу и возвращает Promise. Цвет кнопки лишь сообщает, что произошло.

import { useState } from "react";
import { Button } from "@/components/ui/button";

export function SaveControl({ saveProject }: {
  saveProject: () => Promise<void>;
}) {
  const [state, setState] = useState<"idle" | "saving" | "done" | "error">("idle");
  const busy = state === "saving";

  async function save() {
    if (busy) return;
    setState("saving");
    try { await saveProject(); setState("done"); }
    catch { setState("error"); }
  }

  return <>
    <Button type="button" disabled={busy} aria-busy={busy}
      variant={state === "error" ? "destructive" : "default"}
      onClick={save}>
      {busy ? "Сохраняем…" : "Сохранить настройки"}
    </Button>
    <p aria-live="polite">
      {state === "done" ? "Настройки сохранены." :
       state === "error" ? "Не удалось сохранить. Повторите попытку." : ""}
    </p>
  </>;
}

Пока операция идёт, повторное нажатие недоступно; после ошибки пользователь получает способ повторить действие. Успех показываем только после завершения Promise. В настоящем приложении дополните сообщение полезной причиной сбоя, а на сервере предусмотрите защиту от повторной обработки важной операции.

aria-busy сообщает о промежуточном состоянии, aria-live помогает озвучить результат без ручного перевода фокуса. Они не заменяют видимую подпись. Не сообщайте об успешном сохранении только зелёной рамкой: её значение должно подтверждаться текстом.

Диалоги и вкладки: поведение важнее декоративной рамки

Часть интерактивных компонентов Cosmic UI использует Zag.js. Его машина состояний определяет, какие переходы допустимы, а connect связывает их с DOM-атрибутами и событиями. Для диалога важны открытие, закрытие и фокус; для вкладок — выбранный раздел и перемещение между переключателями. Это отдельная задача от бизнес-состояний кнопки сохранения выше.

Польза такого подхода проявляется при нескольких способах управления одним элементом. Окно можно открыть кнопкой, закрыть Escape или действием внутри; приложение тоже может изменить open. Согласованная логика должна привести все эти пути к одному результату. Упрощённо маршрут выглядит так:

Исходное состояние Событие Что меняется для пользователя
Окно закрыто Активирована кнопка открытия Окно появляется, фокус переходит внутрь
Окно открыто Нажата Tab Фокус движется между доступными элементами окна
Окно открыто Нажата Escape или кнопка отмены Окно закрывается, фокус возвращается к вызвавшему элементу

Таблица описывает ожидаемое поведение модального режима, а не внутренние имена узлов Zag. Разработчику полезно мыслить такими переходами: тогда после смены разметки он проверяет целый сценарий, а не только значение одного boolean.

Модальный диалог подходит для короткого действия, требующего внимания. Заголовок объясняет цель, описание — последствия, кнопки позволяют продолжить или отказаться. Собственный пример ниже использует реальные части API Cosmic UI; callback resetDraft задаёт действие приложения.

import { useState } from "react";
import { Button } from "@/components/ui/button";
import { DialogRoot, DialogTrigger, DialogContent, DialogTitle,
  DialogDescription, DialogCloseTrigger } from "@/components/ui/dialog";

export function ResetDialog({ resetDraft }: { resetDraft: () => void }) {
  const [open, setOpen] = useState(false);
  return <DialogRoot open={open} onOpenChange={({ open }) => setOpen(open)}>
    <DialogTrigger>Сбросить черновик</DialogTrigger>
    <DialogContent>
      <DialogTitle>Вернуть начальные настройки?</DialogTitle>
      <DialogDescription>Текущие настройки черновика будут заменены.</DialogDescription>
      <DialogCloseTrigger asChild>
        <Button type="button" variant="secondary">Оставить как есть</Button>
      </DialogCloseTrigger>
      <Button type="button" variant="destructive" onClick={() => {
        resetDraft(); setOpen(false);
      }}>Сбросить</Button>
    </DialogContent>
  </DialogRoot>;
}

Здесь состояние open контролирует наше приложение. DialogContent уже включает портал и подложку, поэтому дополнительная внешняя подложка не нужна. asChild у закрывающего элемента позволяет передать действие обычному Button. Это свойство не следует автоматически переносить на все остальные части API.

Проверьте, что после открытия фокус оказался внутри окна, Tab не уходит в фон страницы, Escape закрывает окно, а затем фокус возвращается к вызвавшей его кнопке. Для необратимого действия первым доступным выбором удобно оставить отказ. Если сохранение асинхронное, не закрывайте окно до ответа: покажите ожидание и ошибку внутри него.

Для вкладок используйте TabsRoot, TabsList, TabsTrigger и TabsContent. Значение value переключателя должно совпадать со значением его панели; defaultValue задаёт начальный раздел. Вкладки помогают переключать представления одного контекста, например «Обзор», «Параметры», «Журнал». Разные страницы сайта лучше оставлять ссылками с отдельными адресами.

В проверенном исходнике Cosmic UI содержимое TabsContent обёрнуто в параграф. Короткий текст туда подходит; сложная форма, таблица или вложенные блочные элементы требуют пересмотра этой разметки. Проверяйте полученный DOM, а не только внешний вид: библиотечный пример может нуждаться в адаптации под ваш сценарий.

Доступность и мобильный экран: проверьте реальную задачу

Наличие машины состояний помогает с клавиатурой и ARIA, но не гарантирует доступность готового экрана. Названия, контраст, размеры, порядок элементов и содержимое задаёт автор приложения. Декоративная рамка тоже не должна перехватывать нажатия или заменять настоящий button.

  • Клавиатура. Пройдите экран Tab и Shift+Tab. Фокус должен быть заметным. Обычная кнопка должна срабатывать с клавиатуры, а порядок переходов — соответствовать чтению страницы.
  • Поля. Дайте каждому полю видимую подпись. Placeholder может исчезнуть после ввода, поэтому он не заменяет label. Ошибка должна объяснять, что исправить.
  • Цвет. Проверяйте текст на фактическом фоне и не кодируйте смысл только оттенком. Выбранный режим должен отличаться от простого наведения.
  • Движение. Для добавленных анимаций учитывайте prefers-reduced-motion. Состояние и результат должны быть понятны при отключённых эффектах.
  • Мобильный экран. Уберите жёсткую ширину, проверьте длинные русские подписи, перенос действий и прокрутку открытого диалога. Эффект наведения не должен быть единственным способом узнать назначение элемента.

Проверяйте доступность в конкретном сценарии: открыть настройки, изменить значение, сохранить, увидеть результат, вернуться к исходному экрану. Такой маршрут быстро выявляет исчезающий фокус, кнопку за пределами окна и непонятную ошибку. Красивый скриншот этих проблем не показывает.

Как перенести пример в проект и развивать его дальше

Начните с одного небольшого экрана и нескольких нужных компонентов. Отделите настройки темы от содержимого, а демонстрационные действия — от реальной логики приложения. После первого рабочего сценария добавляйте поля, уведомления и дополнительные панели. Это позволяет проверять целое действие после каждого изменения.

Архив на площадке содержит наш учебный проект и README. После распаковки выполните npm ci, затем npm run setup и npm run dev. Setup получает официальные компоненты из зафиксированной ревизии репозитория и проверяет контрольные суммы файлов. Такой путь отличается от CLI-команд выше, которые предназначены для добавления компонентов в ваш существующий проект и обращаются к текущему реестру.

В исходниках примера полезно сохранять README, lockfile, перечень зависимостей и точную версию использованных компонентов. CLI переносит код в проект, поэтому обновление требует сравнения собственных изменений с новым исходником. Не заменяйте настроенные файлы вслепую: сначала посмотрите различия, затем проверьте импорт, тему, клавиатуру и основной сценарий.

Условия разных частей проекта тоже проверяйте отдельно. На дату подготовки материала MIT указана в package.json официального CLI; отдельный общий файл LICENSE для корня репозитория не обнаружен. Это не основание объявлять весь набор компонентов и его ресурсы MIT. Инструкции установки и примеры доступны на официальном сайте Cosmic UI; для распространяемого проекта сохраняйте фактические уведомления и сведения о его составе.

Характер интерфейса появляется из согласованных решений: одна палитра, понятные действия, аккуратные состояния и устойчивое поведение. Начните с кнопки и небольшого окна настроек, проверьте их без мыши и на телефоне, затем расширяйте экран. Так Cosmic UI становится основой полезного интерфейса, а декоративные детали поддерживают его задачу.