Radix UI представляет собой набор полностью доступных компонентов интерфейса, реализованных как headless-компоненты, что позволяет разработчикам полностью контролировать стилизацию и поведение. При использовании с Next.js важно учитывать особенности серверного рендеринга (SSR) и маршрутизации, чтобы компоненты корректно отображались как на сервере, так и на клиенте.
Компоненты Radix UI предоставляют минимальную оболочку и требуют стилизации с помощью CSS или CSS-in-JS. В Next.js это удобно комбинировать с библиотеками вроде Tailwind CSS, Stitches или Vanilla Extract, что обеспечивает высокую гибкость и поддерживаемость.
Next.js по умолчанию рендерит страницы на сервере, а затем
“гидратирует” их на клиенте. Radix UI использует React и
зависит от состояния компонента (например, открытое меню или диалог),
что может привести к проблемам при несоответствии состояния на
сервере и клиенте. Основные рекомендации:
typeof window !== 'undefined' для
рендеринга компонентов, зависящих от браузерного окружения.useEffect для действий, которые должны
выполняться только на клиенте (например, динамическая установка
фокуса).document или
window при SSR без проверки.Пример безопасного рендеринга модального окна:
import { Dialog } from '@radix-ui/react-dialog';
import { useState, useEffect } from 'react';
export default function ClientOnlyDialog() {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return null;
return (
<Dialog>
<Dialog.Trigger>Открыть диалог</Dialog.Trigger>
<Dialog.Content>
<p>Содержимое диалога</p>
<Dialog.Close>Закрыть</Dialog.Close>
</Dialog.Content>
</Dialog>
);
}
Radix UI не навязывает стили, поэтому необходимо самостоятельно оформлять компоненты. В Next.js популярны следующие подходы:
<Dialog.Content className="bg-white p-6 rounded shadow-lg">
<Dialog.Title className="text-xl font-bold">Заголовок</Dialog.Title>
<Dialog.Description className="text-gray-600">Описание диалога</Dialog.Description>
</Dialog.Content>
import { styled } from '@stitches/react';
import * as Dialog from '@radix-ui/react-dialog';
const StyledContent = styled(Dialog.Content, {
backgroundColor: 'white',
padding: '2rem',
borderRadius: '8px',
boxShadow: '0 10px 25px rgba(0,0,0,0.2)',
});
export default function MyDialog() {
return (
<Dialog.Root>
<Dialog.Trigger>Открыть</Dialog.Trigger>
<StyledContent>
<Dialog.Title>Заголовок</Dialog.Title>
</StyledContent>
</Dialog.Root>
);
}
Radix UI предлагает контролируемые и неконтролируемые компоненты. В Next.js лучше использовать контролируемый режим для обеспечения предсказуемого поведения при SSR.
Пример контролируемого селекта:
import * as Sel ect from '@radix-ui/react-select';
import { useState } fr om 'react';
export default function ControlledSelect() {
const [value, setValue] = useState('option1');
return (
<Sel ect.Root value={value} onValueCha nge={setValue}>
<Sel ect.Trigger>{value}</Sel ect.Trigger>
<Select.Content>
<Select.Item value="option1">Опция 1</Select.Item>
<Select.Item value="option2">Опция 2</Select.Item>
</Select.Content>
</Select.Root>
);
}
Компоненты Radix UI часто используют ссылки и действия, которые могут взаимодействовать с маршрутизацией. Для корректной работы с Next.js необходимо:
<Link> из next/link для
переходов.window.location без проверки
SSR.Пример интеграции Radix Dialog с маршрутизацией:
import Link fr om 'next/link';
import * as Dialog fr om '@radix-ui/react-dialog';
export default function NavigationDialog() {
return (
<Dialog.Root>
<Dialog.Trigger>Меню</Dialog.Trigger>
<Dialog.Content>
<Link href="/about">О нас</Link>
<Link href="/contact">Контакты</Link>
<Dialog.Close>Закрыть</Dialog.Close>
</Dialog.Content>
</Dialog.Root>
);
}
Radix UI автоматически управляет фокусом, ролями и aria-атрибутами, что критично для доступности. В Next.js необходимо учитывать:
Next.js позволяет использовать динамический импорт для компонентов Radix UI, что снижает нагрузку на клиент:
import dynamic fr om 'next/dynamic';
const DynamicDialog = dynamic(() => import('./DialogComponent'), { ssr: false });
export default function Page() {
return <DynamicDialog />;
}
Это особенно полезно для компонентов, требующих интерактивности, таких как модальные окна, аккордеоны, меню и тултипы.
Эта структура обеспечивает полное использование возможностей Radix UI в Next.js с учетом особенностей SSR, маршрутизации, стилизации и управления состоянием, что позволяет создавать доступные, гибкие и производительные интерфейсы.