PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Дизайн-система в React с нуля: токены, компоненты и Storybook

    Дизайн-система в React с нуля: токены, компоненты и Storybook

    Аватар автора Дизайн-система в React с нуля: токены, компоненты и Storybook

    Антон Ларичев

    Иконка календаря20 марта 2026
    reacttypescriptcssmiddleИконка уровня middle
    Картинка поста Дизайн-система в React с нуля: токены, компоненты и Storybook

    Введение

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

    В этой статье разберём, как построить дизайн-систему в React с нуля: от определения дизайн-токенов до создания компонентов и их документирования в Storybook. Рассмотрим практический пример с TypeScript и CSS-переменными.

    Что такое дизайн-токены и зачем они нужны

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

    Трёхуровневая структура токенов помогает масштабировать систему:

    // tokens/colors.ts — базовые (core) токены
    export const coreColors = {
      purple100: '#f3e8ff',
      purple500: '#8b5cf6',
      purple900: '#4c1d95',
      gray100: '#f3f4f6',
      gray900: '#111827',
      white: '#ffffff',
    } as const;
    
    // tokens/semantic.ts — семантические токены
    export const semanticColors = {
      textPrimary: coreColors.gray900,
      textSecondary: coreColors.purple900,
      backgroundPrimary: coreColors.white,
      backgroundAccent: coreColors.purple100,
      borderDefault: coreColors.gray100,
      brandPrimary: coreColors.purple500,
    } as const;
    

    Семантические токены не привязаны к конкретному цвету — они описывают назначение. Это позволяет легко добавить тёмную тему, поменяв только маппинг семантических токенов на базовые.

    Как превратить токены в CSS-переменные

    Чтобы дизайн-токены работали в стилях, преобразуем их в CSS-переменные:

    // tokens/cssVariables.ts
    import { semanticColors } from './semantic';
    
    export function applyTokens(element: HTMLElement = document.documentElement) {
      const tokenMap: Record<string, string> = {
        '--color-text-primary': semanticColors.textPrimary,
        '--color-text-secondary': semanticColors.textSecondary,
        '--color-bg-primary': semanticColors.backgroundPrimary,
        '--color-bg-accent': semanticColors.backgroundAccent,
        '--color-border': semanticColors.borderDefault,
        '--color-brand': semanticColors.brandPrimary,
      };
    
      Object.entries(tokenMap).forEach(([key, value]) => {
        element.style.setProperty(key, value);
      });
    }
    

    Теперь в CSS компонентов используем переменные вместо жёстких значений:

    .button-primary {
      background-color: var(--color-brand);
      color: var(--color-bg-primary);
      border-radius: var(--radius-md);
      padding: var(--spacing-sm) var(--spacing-md);
    }
    

    Как создать компоненты дизайн-системы в React

    Компоненты дизайн-системы строятся по принципу Atomic Design: от простых атомов (кнопка, инпут) к молекулам (поле ввода с лейблом) и организмам (форма). Начнём с базового компонента Button.

    // components/Button/Button.tsx
    import React from 'react';
    import styles from './Button.module.css';
    
    type ButtonVariant = 'primary' | 'secondary' | 'ghost';
    type ButtonSize = 'sm' | 'md' | 'lg';
    
    interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
      variant?: ButtonVariant;
      size?: ButtonSize;
      isLoading?: boolean;
    }
    
    export const Button: React.FC<ButtonProps> = ({
      variant = 'primary',
      size = 'md',
      isLoading = false,
      children,
      disabled,
      className,
      ...props
    }) => {
      return (
        <button
          className={`${styles.button} ${styles[variant]} ${styles[size]} ${className ?? ''}`}
          disabled={disabled || isLoading}
          {...props}
        >
          {isLoading ? <span className={styles.spinner} /> : children}
        </button>
      );
    };
    
    /* components/Button/Button.module.css */
    .button {
      font-family: var(--font-family);
      font-weight: 500;
      border: none;
      cursor: pointer;
      transition: background-color 0.2s, opacity 0.2s;
    }
    
    .primary {
      background-color: var(--color-brand);
      color: var(--color-bg-primary);
    }
    
    .secondary {
      background-color: var(--color-bg-accent);
      color: var(--color-text-secondary);
    }
    
    .ghost {
      background-color: transparent;
      color: var(--color-text-primary);
    }
    
    .sm { padding: var(--spacing-xs) var(--spacing-sm); font-size: 14px; }
    .md { padding: var(--spacing-sm) var(--spacing-md); font-size: 16px; }
    .lg { padding: var(--spacing-md) var(--spacing-lg); font-size: 18px; }
    
    .button:disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
    

    Каждый компонент дизайн-системы использует токены через CSS-переменные. Если дизайнер изменит основной цвет бренда — достаточно обновить один токен, и все компоненты подхватят изменение.

    Как настроить Storybook для React компонентов

    Storybook позволяет разрабатывать и документировать компоненты UI kit изолированно от основного приложения. Установка:

    npx storybook@latest init
    

    После инициализации создаём stories для компонентов:

    // components/Button/Button.stories.tsx
    import type { Meta, StoryObj } from '@storybook/react';
    import { Button } from './Button';
    
    const meta: Meta<typeof Button> = {
      title: 'Components/Button',
      component: Button,
      argTypes: {
        variant: {
          control: 'select',
          options: ['primary', 'secondary', 'ghost'],
        },
        size: {
          control: 'select',
          options: ['sm', 'md', 'lg'],
        },
      },
    };
    
    export default meta;
    type Story = StoryObj<typeof Button>;
    
    // Основной вариант кнопки
    export const Primary: Story = {
      args: {
        children: 'Отправить',
        variant: 'primary',
        size: 'md',
      },
    };
    
    // Вторичный вариант
    export const Secondary: Story = {
      args: {
        children: 'Отмена',
        variant: 'secondary',
      },
    };
    
    // Состояние загрузки
    export const Loading: Story = {
      args: {
        children: 'Сохранение...',
        isLoading: true,
      },
    };
    

    Для документирования токенов используйте аддон storybook-design-token, который автоматически генерирует таблицы цветов, шрифтов и отступов из CSS-переменных:

    npm install storybook-design-token
    

    Частые ошибки при создании дизайн-системы

    Жёсткие значения вместо токенов. Если в компоненте написано color: #8b5cf6 вместо var(--color-brand), при смене темы этот компонент останется прежним. Все визуальные значения должны идти через токены.

    Слишком много вариантов у компонента. Кнопка с 15 пропсами сложнее в поддержке, чем три отдельных компонента. Начинайте с минимального API и расширяйте по мере реальных потребностей.

    Отсутствие документации. Компонент без Story в Storybook — это компонент, который никто не будет переиспользовать. Документируйте каждый компонент сразу при создании.

    Пропуск семантического уровня токенов. Если компоненты ссылаются напрямую на purple500, добавление тёмной темы потребует правок в каждом файле. Семантический слой (brandPrimary) решает эту проблему.

    Заключение

    Дизайн-система в React — это инвестиция, которая окупается с ростом проекта. Начните с определения дизайн-токенов на трёх уровнях (базовые, семантические, компонентные), создайте переиспользуемые компоненты с минимальным API и задокументируйте их в Storybook. Такой подход обеспечит консистентность интерфейса, ускорит разработку и упростит поддержку тем оформления.

    Иконка глаза457

    Комментарии

    0

    Постройте личный план изучения Neovim - практика и настройка до уровня Middle — бесплатно!

    Neovim - практика и настройка — часть карты развития Frontend, Backend, DevOps

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    React и Redux Toolkit

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Zustand

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Next.js - с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Паттерны проектирования на TypeScript: SOLID с примерами
    Иконка аватараАнтон
    Иконка календаря13 июня 2026
    typescriptsolidпаттерны проектирования+ 2middleИконка уровня middle

    Паттерны проектирования на TypeScript: SOLID с примерами

    Паттерны проектирования на TypeScript и принципы SOLID: разбор каждого принципа с практическими примерами кода, типичными ошибками и рекомендациями.

    Иконка чипа0
    Иконка глаза310
    Иконка комментариев0
    Картинка поста TypeScript дженерики на практике: полный гайд для разработчиков
    Иконка аватараАнтон
    Иконка календаря30 мая 2026
    typescriptgenericsjavascript+ 1middleИконка уровня middle

    TypeScript дженерики на практике: полный гайд для разработчиков

    TypeScript дженерики на практике: разбираем синтаксис, ограничения, условные типы и реальные примеры использования в проектах.

    Иконка чипа0
    Иконка глаза414
    Иконка комментариев0
    Картинка поста CI/CD пайплайн в GitHub Actions для Next.js: полный гайд
    Иконка аватараАнтон
    Иконка календаря18 июня 2026
    GitHub ActionsCI/CDNext.js+ 2middleИконка уровня middle

    CI/CD пайплайн в GitHub Actions для Next.js: полный гайд

    CI/CD пайплайн в GitHub Actions для Next.js: настройка автоматической сборки, тестирования и деплоя приложения с примерами workflow-файлов и разбором типичных ошибок.

    Иконка чипа0
    Иконка глаза203
    Иконка комментариев0
    Иконка чипа0