Tailwind CSS и Radix UI

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

Tailwind CSS предоставляет утилитарный подход к стилизации, позволяя задавать классы напрямую в JSX. Основная задача при работе с Radix UI — обеспечить корректное отображение и взаимодействие компонентов при помощи классов Tailwind.


Использование className с Radix компонентами

Практически каждый компонент Radix поддерживает стандартный проп className. Для адаптации под Tailwind CSS необходимо:

import * as Dialog from '@radix-ui/react-dialog';

function Example() {
  return (
    <Dialog.Root>
      <Dialog.Trigger className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
        Открыть
      </Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-50" />
        <Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg shadow-lg">
          <Dialog.Title className="text-lg font-semibold">Заголовок модального окна</Dialog.Title>
          <Dialog.Description className="text-sm text-gray-500">
            Подробное описание содержимого модального окна.
          </Dialog.Description>
          <Dialog.Close className="mt-4 px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700">
            Закрыть
          </Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}

Ключевые моменты:

  • Dialog.Trigger — кнопка открытия, стилизуется как обычная кнопка Tailwind.
  • Dialog.Overlay — полупрозрачный фон, покрывающий весь экран.
  • Dialog.Content — основной контейнер модального окна с позиционированием и тенью.
  • Dialog.Title и Dialog.Description — семантические элементы с возможностью кастомной типографики.

Работа с состояния через Tailwind

Radix предоставляет различные состояния компонентов: открыто/закрыто, фокус, активное состояние, выбор элемента. Tailwind CSS поддерживает псевдоклассы, что позволяет связать эти состояния с динамическими классами.

Пример с Tabs:

import * as Tabs from '@radix-ui/react-tabs';

function TabsExample() {
  return (
    <Tabs.Root defaultValue="tab1" className="w-full">
      <Tabs.List className="flex border-b border-gray-300">
        <Tabs.Trigger
          value="tab1"
          className="px-4 py-2 text-gray-700 data-[state=active]:border-b-2 data-[state=active]:border-blue-600 data-[state=active]:text-blue-600"
        >
          Вкладка 1
        </Tabs.Trigger>
        <Tabs.Trigger
          value="tab2"
          className="px-4 py-2 text-gray-700 data-[state=active]:border-b-2 data-[state=active]:border-blue-600 data-[state=active]:text-blue-600"
        >
          Вкладка 2
        </Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1" className="p-4">
        Содержимое первой вкладки
      </Tabs.Content>
      <Tabs.Content value="tab2" className="p-4">
        Содержимое второй вкладки
      </Tabs.Content>
    </Tabs.Root>
  );
}

Особенности:

  • Атрибуты data-[state=active] позволяют Tailwind применять стили для активного состояния.
  • Стандартные состояния Radix (open, checked, disabled) можно использовать через селекторы [data-state=...] и [data-disabled].

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

Radix UI не навязывает анимации, что полностью соответствует утилитарному подходу Tailwind. Для анимации открывающихся компонентов используют классы Tailwind с поддержкой transition и duration.

Пример анимации модального окна:

<Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg shadow-lg
  data-[state=open]:animate-fadeIn data-[state=closed]:animate-fadeOut"
>
  ...
</Dialog.Content>

Tailwind CSS конфиг может быть расширен, чтобы добавить кастомные анимации:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        fadeIn: { '0%': { opacity: 0 }, '100%': { opacity: 1 } },
        fadeOut: { '0%': { opacity: 1 }, '100%': { opacity: 0 } },
      },
      animation: {
        fadeIn: 'fadeIn 0.2s ease-out',
        fadeOut: 'fadeOut 0.2s ease-out',
      },
    },
  },
};

Составные компоненты и переиспользуемые стили

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

Пример обертки для кнопки с состояниями Radix:

import * as Toggle from '@radix-ui/react-toggle';

const ButtonToggle = ({ children, className, ...props }) => (
  <Toggle.Root
    className={`px-4 py-2 rounded-md border border-gray-300
      data-[state=on]:bg-blue-600 data-[state=on]:text-white
      hover:bg-gray-100 transition-colors ${className}`}
    {...props}
  >
    {children}
  </Toggle.Root>
);

Преимущества:

  • Унифицированный стиль для всех toggle-кнопок.
  • Поддержка Tailwind утилит и псевдоклассов состояния.
  • Легкая адаптация под дизайн-систему без изменения логики Radix.

Настройка темизации

Tailwind CSS с Radix позволяет использовать переменные CSS для цветов и тем. Radix предоставляет возможность передавать style или использовать CSS-переменные для динамической темы.

<Dialog.Content
  style={{ '--dialog-bg': 'theme(colors.white)' }}
  className="bg-[var(--dialog-bg)] p-6 rounded-lg shadow-lg"
>
  ...
</Dialog.Content>

Такой подход упрощает интеграцию с Dark Mode Tailwind:

className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"

Полезные советы по структуре

  1. Разделение логики и стиля: Radix отвечает за поведение и доступность, Tailwind — за визуальное оформление.
  2. Использование data-атрибутов: [data-state], [data-disabled] позволяют писать чистые условные стили.
  3. Порталы и Overlay: всегда использовать Dialog.Portal и Popover.Portal для корректного позиционирования и z-index.
  4. Адаптивность: Tailwind утилиты sm:, md:, lg: полностью применимы к Radix компонентам.

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