Темизация компонентов

Radix UI предоставляет набор высоко настраиваемых компонентов для React, при этом основной подход к темизации строится на CSS-переменных и системах стилей, совместимых с CSS-in-JS и Tailwind. Каждый компонент Radix UI использует структуру слотов и классов, что позволяет внедрять кастомные темы без изменения исходного кода библиотеки.

Главная идея — разделение логики компонента и внешнего вида, что обеспечивает гибкость и масштабируемость. Темизация может осуществляться на нескольких уровнях:

  1. Глобальные переменные темы — задаются для всей библиотеки и используются всеми компонентами.
  2. Локальные переменные и классы — применяются для отдельных компонентов или их состояний.
  3. Комбинирование с системами стилей — позволяет интегрировать Radix с Tailwind, Stitches, Vanilla Extract или Emotion.

Использование CSS-переменных для темы

Radix UI активно использует подход с CSS-переменными. В качестве примера, для кнопки можно определить базовые переменные:

:root {
  --button-bg: #1f2937;
  --button-text: #f9fafb;
  --button-hover-bg: #374151;
}

В компоненте эти переменные применяются через стили:

import { Button } from '@radix-ui/react-button';
import './button.css';

<Button style={{
  backgroundColor: 'var(--button-bg)',
  color: 'var(--button-text)'
}}>
  Кнопка
</Button>

Преимущество: при смене темы достаточно изменить значения переменных, а компоненты автоматически адаптируются.


Темизация через Stitches

Для более динамичных решений часто используется Stitches — CSS-in-JS библиотека, рекомендуемая Radix. Она позволяет создавать варианты и темы, управлять состояниями компонента напрямую.

import { styled } from '@stitches/react';
import { Button as RadixButton } from '@radix-ui/react-button';

const Button = styled(RadixButton, {
  variants: {
    variant: {
      primary: { backgroundColor: '$primary', color: '$onPrimary' },
      secondary: { backgroundColor: '$secondary', color: '$onSecondary' }
    },
    size: {
      small: { padding: '4px 8px', fontSize: '12px' },
      large: { padding: '12px 24px', fontSize: '16px' }
    }
  }
});

// Применение темы
<Button variant="primary" size="large">Пример</Button>

Здесь $primary и $secondary — ключи темы, которые можно менять через createTheme для динамических светлых и темных режимов.

import { createTheme } from '@stitches/react';

const darkTheme = createTheme({
  colors: {
    primary: '#1f2937',
    onPrimary: '#f9fafb',
    secondary: '#374151',
    onSecondary: '#e5e7eb'
  }
});

Слоты и их роль в темизации

Radix UI использует концепцию slots, что позволяет передавать пользовательские элементы в компоненты с сохранением логики. Это особенно важно для темизации, так как можно менять только визуальную часть, не затрагивая поведение.

import * as Tooltip from '@radix-ui/react-tooltip';

<Tooltip.Root>
  <Tooltip.Trigger>Наведи меня</Tooltip.Trigger>
  <Tooltip.Content className="tooltip-content">
    Текст подсказки
  </Tooltip.Content>
</Tooltip.Root>

С помощью CSS можно управлять стилями .tooltip-content для разных тем:

[data-theme='dark'] .tooltip-content {
  background: #1f2937;
  color: #f9fafb;
}

[data-theme='light'] .tooltip-content {
  background: #f3f4f6;
  color: #111827;
}

Ключевой момент: использование data-theme позволяет переключать тему глобально без переписывания компонентов.


Динамическая смена темы

Для динамической темы часто используют контекст или React state. Например:

import { useState } from 'react';

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <div data-theme={theme}>
      <Button variant="primary">Кнопка</Button>
      <button onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Сменить тему
      </button>
    </div>
  );
}

Компоненты Radix UI автоматически адаптируются к изменениям CSS-переменных или классов, что делает подход полностью реактивным.


Интеграция с Tailwind

Radix UI легко интегрируется с Tailwind CSS, где классы заменяют CSS-переменные, а состояния компонентов управляются через data- атрибуты:

<Button className="bg-gray-800 text-white hover:bg-gray-700">
  Кнопка
</Button>

Для темного режима Tailwind предоставляет директиву dark::

<Button className="bg-white text-black dark:bg-gray-800 dark:text-white">
  Кнопка
</Button>

Radix UI автоматически добавляет необходимые атрибуты для состояний, таких как data-state="open" или data-disabled, что позволяет Tailwind управлять стилями с помощью этих селекторов.


Состояния компонентов и их стили

Все компоненты Radix UI имеют структурированные состояния:

  • data-state — открыто/закрыто (open, closed)
  • data-disabled — отключено
  • data-highlighted — подсвечено

Это позволяет задавать уникальные стили для каждого состояния в рамках темы:

[data-theme='dark'] [data-state='open'] {
  background-color: #374151;
}

[data-theme='light'] [data-disabled] {
  opacity: 0.5;
}

Рекомендации по построению тем

  1. Соблюдать модульность: темы должны быть независимыми от конкретных компонентов.
  2. Использовать переменные для повторяющихся цветов и размеров.
  3. Поддерживать состояния через data-атрибуты.
  4. Разделять глобальные и локальные темы, чтобы иметь гибкость при создании сложных интерфейсов.
  5. Тестировать тему в разных компонентах Radix UI, чтобы убедиться в консистентности визуального стиля.

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