Темная тема

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

Управление темой через CSS-переменные

Radix UI использует подход с CSS-переменными для управления цветами и стилями компонентов. Для реализации темной темы рекомендуется определять отдельный набор переменных для светлой и темной темы:

:root {
  --color-background: #ffffff;
  --color-text: #000000;
  --color-primary: #4f46e5;
}

[data-theme="dark"] {
  --color-background: #1f2937;
  --color-text: #f9fafb;
  --color-primary: #6366f1;
}

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

Использование Radix Provider для темы

Хотя Radix UI не навязывает конкретного способа управления темой, удобно использовать контекст React для хранения состояния текущей темы:

import { createContext, useContext, useState } from "react";

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  const toggleTheme = () => {
    const newTheme = theme === "light" ? "dark" : "light";
    document.documentElement.setAttribute("data-theme", newTheme);
    setTheme(newTheme);
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export const useTheme = () => useContext(ThemeContext);

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

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

Radix UI отлично сочетается с Tailwind CSS. Для поддержки темной темы через Tailwind можно использовать dark: модификаторы и сочетать их с CSS-переменными, заданными через [data-theme="dark"]:

<button className="bg-primary text-background dark:bg-primary-dark dark:text-background-dark">
  Нажми меня
</button>

Также можно определить Tailwind-конфигурацию для автоматического переключения темы:

module.exports = {
  darkMode: ["class", '[data-theme="dark"]'],
  theme: {
    extend: {
      colors: {
        background: "var(--color-background)",
        text: "var(--color-text)",
        primary: "var(--color-primary)",
      },
    },
  },
};

Динамическое обновление темы

Для компонентов, которые активно используют состояние, важно корректно реагировать на изменение темы в реальном времени. Radix UI-компоненты, такие как Dialog, DropdownMenu, Tabs, Toast, не хранят собственных цветов и используют CSS для визуализации. Поэтому переключение темы через document.documentElement.setAttribute("data-theme", ...) немедленно изменяет внешний вид всех компонентов.

Пример динамического обновления темы с кнопкой переключения:

import { useTheme } from "./ThemeProvider";

export function ThemeToggleButton() {
  const { theme, toggleTheme } = useTheme();

  return (
    <button onCl ick={toggleTheme} className="px-4 py-2 bg-primary text-background">
      {theme === "light" ? "Включить темную тему" : "Включить светлую тему"}
    </button>
  );
}

Специфические стили для Radix-компонентов

Некоторые компоненты требуют дополнительных стилей для полного соответствия темной теме:

  • Toast: фон и текст задаются через CSS-переменные, чтобы уведомления выглядели гармонично в обеих темах.
  • Select: раскрывающийся список (SelectContent) необходимо стилизовать отдельно, так как его портал может рендериться вне основного DOM.
[data-theme="dark"] .select-content {
  background-color: var(--color-background);
  color: var(--color-text);
  border: 1px solid #374151;
}
  • Tabs: активная вкладка может использовать --color-primary, а не фиксированный цвет, чтобы соответствовать текущей теме.

Советы по организации тем

  1. Централизовать переменные: хранить все ключевые цвета и размеры в одном файле theme.css.
  2. Использовать контекст: для глобального доступа к текущей теме через React.
  3. Обновлять данные theme на корневом элементе: это гарантирует, что любые Radix UI-порталы и модальные окна наследуют нужные стили.
  4. Тестировать компоненты в обеих темах: особенно важно для интерактивных элементов с анимациями и тенями.

Итоговый подход

Radix UI не привязывает к конкретной системе тем, но идеальная практика включает:

  • Использование CSS-переменных для всех ключевых цветов.
  • Управление текущей темой через атрибут data-theme на <html> или <body>.
  • Интеграцию с контекстом React для централизованного переключения.
  • Настройку Tailwind CSS для использования переменных и поддержки темного режима.

Такой подход обеспечивает полную адаптивность интерфейса, мгновенное переключение тем и сохранение консистентного визуального стиля всех компонентов Radix UI.