Emotion

Radix UI предоставляет низкоуровневые компоненты для построения интерфейсов с управляемым состоянием и доступностью. Для интеграции с Emotion необходимо использовать компонент styled из @emotion/styled или хук css из @emotion/react. Это позволяет полностью контролировать стили, сохраняя доступность и функциональность компонентов Radix.

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import * as Dialog from '@radix-ui/react-dialog';

const StyledDialogContent = styled(Dialog.Content)`
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
`;

Использование styled обеспечивает возможность создавать переиспользуемые компоненты с заранее заданными стилями, сохраняя все свойства Radix UI, включая анимации, фокус и aria-атрибуты.


Стилизация через css и динамические пропсы

Использование хука css позволяет добавлять динамические стили на основе пропсов компонента:

const buttonStyle = (primary) => css`
  padding: 10px 20px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  background-color: ${primary ? 'blue' : 'gray'};
  color: white;
  &:hover {
    background-color: ${primary ? 'darkblue' : 'darkgray'};
  }
`;

function MyButton({ primary, children }) {
  return <button css={buttonStyle(primary)}>{children}</button>;
}

При работе с Radix UI можно комбинировать компоненты Radix и стилизованные Emotion-элементы, создавая полностью кастомные интерфейсы с сохранением состояния компонента и доступности.


Анимации и transition

Radix UI предоставляет свойства состояния для управления анимациями (open, closed). Emotion позволяет применять эти состояния в стилях с помощью селекторов и CSS-переменных.

const StyledContent = styled(Dialog.Content)`
  opacity: 0;
  transform: translateY(-10px);
  transition: all 0.3s ease;

  &[data-state='open'] {
    opacity: 1;
    transform: translateY(0);
  }
`;

Здесь используется атрибут data-state, который Radix UI автоматически добавляет к компоненту в зависимости от его состояния. Это обеспечивает плавное появление и скрытие диалогов без использования дополнительных библиотек анимации.


Комбинирование Radix UI с темизацией

Emotion поддерживает создание тем через ThemeProvider, что позволяет централизованно управлять цветами, отступами и типографикой для компонентов Radix:

import { ThemeProvider } from '@emotion/react';

const theme = {
  colors: {
    primary: 'blue',
    secondary: 'gray',
    background: '#f9f9f9',
  },
  borderRadius: '8px',
};

const StyledDialogContent = styled(Dialog.Content)`
  background-color: ${props => props.theme.colors.background};
  border-radius: ${props => props.theme.borderRadius};
  padding: 20px;
`;

Тематизация позволяет создавать единообразный дизайн, минимизируя дублирование стилей и улучшая поддержку крупных проектов.


Компоненты с композиционной стилизацией

Radix UI ориентирован на композицию: отдельные части компонента (например, Dialog.Overlay, Dialog.Content) можно стилизовать независимо друг от друга:

const Overlay = styled(Dialog.Overlay)`
  background-color: rgba(0, 0, 0, 0.5);
  position: fixed;
  inset: 0;
`;

const Content = styled(Dialog.Content)`
  background: white;
  border-radius: 10px;
  padding: 25px;
  max-width: 500px;
  margin: 100px auto;
  position: relative;
`;

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


Доступность и стили

Стилизация через Emotion не мешает встроенной доступности Radix UI. Все aria-атрибуты и фокус-менеджмент сохраняются. Для улучшения UX можно добавлять визуальные индикаторы фокуса:

const FocusableButton = styled.button`
  padding: 10px 15px;
  border: 2px solid transparent;
  border-radius: 6px;
  &:focus {
    border-color: blue;
    outline: none;
  }
`;

Это особенно важно для клавиатурной навигации и пользователей с особыми потребностями, так как Radix UI управляет фокусом внутри компонентов, а Emotion только визуализирует состояние.


Практика: модальный диалог с Radix и Emotion

Полный пример объединяет все предыдущие техники:

function App() {
  return (
    <Dialog.Root>
      <Dialog.Trigger asChild>
        <button>Открыть диалог</button>
      </Dialog.Trigger>
      <Overlay />
      <Content>
        <Dialog.Title>Заголовок диалога</Dialog.Title>
        <Dialog.Description>
          Это описание диалога, стилизованного через Emotion.
        </Dialog.Description>
        <button onCl ick={() => Dialog.Root.close()}>Закрыть</button>
      </Content>
    </Dialog.Root>
  );
}

Этот пример демонстрирует:

  • Полную интеграцию с Emotion (styled для контейнеров и overlay)
  • Управление состоянием через Radix UI (open/closed)
  • Поддержку доступности (aria, фокус)
  • Возможность легко расширять стили и добавлять темы

Оптимизация производительности

При использовании Emotion с Radix UI следует учитывать:

  • Стили, создаваемые динамически через пропсы, кешируются.
  • Избегать слишком частого пересоздания css объектов внутри рендер-функций.
  • Использовать styled для повторно используемых компонентов, чтобы минимизировать overhead от генерации CSS на лету.

Эти подходы обеспечивают высокую производительность интерфейсов даже при большом количестве интерактивных компонентов.


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