Интеграция с CSS-in-JS библиотеками

Radix UI предоставляет низкоуровневые, полностью управляемые компоненты для создания пользовательских интерфейсов с высокой степенью доступности. Одним из ключевых преимуществ библиотеки является её безстильный характер, что открывает возможности для гибкой интеграции с любыми системами стилизации, включая CSS-in-JS библиотеки, такие как styled-components, Emotion, Stitches и другие.


Подход к стилизации без стилей по умолчанию

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

  1. Оборачивание Radix компонентов Компонент Radix оборачивается в styled-компонент или оборачивается с помощью функции css библиотеки. Пример с Emotion:
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import * as Dialog from '@radix-ui/react-dialog';

const StyledContent = css`
  background-color: white;
  border-radius: 8px;
  padding: 24px;
  box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
`;

function App() {
  return (
    <Dialog.Root>
      <Dialog.Trigger>Открыть диалог</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay css={{ backgroundColor: 'rgba(0,0,0,0.5)' }} />
        <Dialog.Content css={StyledContent}>
          Контент диалога
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}
  1. Создание кастомных styled-компонентов на базе Radix элементов Для библиотек вроде Stitches или styled-components можно создавать отдельные styled-компоненты, которые расширяют функциональность Radix UI:
import styled from '@stitches/react';
import * as Tabs from '@radix-ui/react-tabs';

const StyledTabList = styled(Tabs.List, {
  display: 'flex',
  borderBottom: '1px solid #eaeaea',
});

const StyledTab = styled(Tabs.Trigger, {
  flex: 1,
  padding: '8px 16px',
  background: 'transparent',
  border: 'none',
  cursor: 'pointer',
  '&[data-state="active"]': {
    borderBottom: '2px solid blue',
    fontWeight: 'bold',
  },
});

Такой подход позволяет сохранять все свойства доступности Radix и при этом полностью контролировать визуальное представление.


Использование динамических стилей

CSS-in-JS библиотеки позволяют использовать props для динамического изменения стиля компонентов Radix. Это особенно удобно для компонентов, где состояние важно для отображения, например, Tabs или Toggle:

const StyledToggle = styled(Tabs.Trigger, {
  padding: '10px 20px',
  borderRadius: '4px',
  border: '1px solid #ccc',
  variants: {
    active: {
      true: { backgroundColor: 'blue', color: 'white' },
      false: { backgroundColor: 'white', color: 'black' },
    },
  },
});

<StyledToggle active={isActive}>Вкладка</StyledToggle>

Radix UI автоматически устанавливает атрибуты состояния, такие как data-state="active", что позволяет напрямую использовать их в стилях CSS-in-JS без дополнительных вычислений.


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

Radix UI поддерживает transition и animation через атрибуты состояния. При использовании CSS-in-JS это удобно:

const StyledAccordionContent = styled(Accordion.Content, {
  overflow: 'hidden',
  variants: {
    open: {
      true: { animation: 'expand 0.3s ease-out forwards' },
      false: { animation: 'collapse 0.3s ease-out forwards' },
    },
  },
});

@keyframes expand {
  from { height: 0; }
  to { height: var(--radix-accordion-content-height); }
}

@keyframes collapse {
  from { height: var(--radix-accordion-content-height); }
  to { height: 0; }
}

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


Работа с псевдоэлементами и состояниями

Radix UI устанавливает data-атрибуты для состояния компонента, что упрощает работу с CSS-in-JS:

  • data-state="open" / "closed" – для Accordion, Dropdown, Dialog.
  • data-state="active" – для Tabs и Toggle.
  • data-disabled – для неактивных элементов.
  • data-highlighted – для элементов меню при навигации с клавиатуры.

В CSS-in-JS это можно использовать напрямую:

const StyledMenuItem = styled(Menu.Item, {
  padding: '8px 16px',
  cursor: 'pointer',
  '&[data-highlighted]': {
    backgroundColor: '#f0f0f0',
  },
  '&[data-disabled]': {
    opacity: 0.5,
    cursor: 'not-allowed',
  },
});

Совместное использование с глобальными темами

CSS-in-JS библиотеки позволяют интегрировать Radix UI с глобальной темой приложения:

const theme = {
  colors: {
    primary: 'blue',
    background: 'white',
    surface: '#f8f8f8',
  },
};

const StyledButton = styled(Dialog.Trigger, {
  backgroundColor: theme.colors.primary,
  color: theme.colors.background,
  padding: '12px 24px',
  borderRadius: '6px',
});

Это обеспечивает консистентность интерфейса при использовании Radix UI в больших проектах с централизованной системой дизайна.


Выводы по интеграции

  • Radix UI предоставляет полный контроль над стилями, что делает его идеальным для проектов с CSS-in-JS.
  • Использование data-атрибутов состояния позволяет легко управлять визуальными эффектами и анимациями.
  • Оборачивание компонентов в styled-компоненты и использование динамических props делает интерфейсы гибкими и масштабируемыми.
  • Совместимость с глобальными темами обеспечивает единый стиль приложения при сохранении всех преимуществ доступности и функциональности Radix UI.

Интеграция Radix UI с CSS-in-JS — это сочетание доступности, управляемости и гибкости стилизации, позволяющее создавать сложные интерфейсы без компромиссов по визуальной части.