Radix UI предоставляет низкоуровневые, доступные компоненты для React, которые легко интегрируются с современными подходами разработки через Hooks. Библиотека ориентирована на контроль состояния компонентов и их взаимодействие с DOM, предоставляя готовые primitives, которые можно кастомизировать с помощью стилей и логики React.
В Radix UI практически каждый компонент предоставляет собственный
механизм управления состоянием. Например, для компонентов
Dialog, Popover,
Accordion или Tabs можно использовать
встроенные состояния, но часто используется подход через
useState или useReducer для более сложной
логики:
import * as Dialog from '@radix-ui/react-dialog';
import { useState } from 'react';
function Example() {
const [open, setOpen] = useState(false);
return (
<Dialog.Root open={open} onOpenCha nge={setOpen}>
<Dialog.Trigger>Открыть диалог</Dialog.Trigger>
<Dialog.Content>
<Dialog.Title>Заголовок</Dialog.Title>
<Dialog.Description>Описание диалога</Dialog.Description>
<Dialog.Close>Закрыть</Dialog.Close>
</Dialog.Content>
</Dialog.Root>
);
}
Ключевые моменты:
open и onOpenChange позволяют полностью
контролировать состояние.useId и других вспомогательных HooksДля создания уникальных идентификаторов, необходимых для
aria атрибутов, Radix рекомендует использовать
useId:
import { useId } from '@radix-ui/react-id';
function CheckboxExample() {
const id = useId();
return (
<>
<label htmlFor={id}>Подтвердить условия</label>
<input type="checkbox" id={id} />
</>
);
}
Преимущества useId:
aria
атрибутами.Radix UI компоненты легко интегрируются с собственными React Hooks
для реализации сложной логики. Например, объединение состояния
Accordion с локальным хранилищем:
import * as Accordion from '@radix-ui/react-accordion';
import { useState, useEffect } from 'react';
function PersistentAccordion() {
const [value, setValue] = useState(() => localStorage.getItem('accordion') || 'item1');
useEffect(() => {
localStorage.setItem('accordion', value);
}, [value]);
return (
<Accordion.Root type="single" value={value} onValueCha nge={setValue}>
<Accordion.Item value="item1">
<Accordion.Header>
<Accordion.Trigger>Секция 1</Accordion.Trigger>
</Accordion.Header>
<Accordion.Content>Контент 1</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item2">
<Accordion.Header>
<Accordion.Trigger>Секция 2</Accordion.Trigger>
</Accordion.Header>
<Accordion.Content>Контент 2</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
}
Особенности такого подхода:
onValueChange в сочетании с
useEffect обеспечивает реактивное обновление
состояния.single и multiple типов
Accordion делает компонент универсальным.Radix UI позволяет использовать компоненты в двух режимах:
useState,
useReducer).Пример неконтролируемого Popover:
import * as Popover from '@radix-ui/react-popover';
function UncontrolledPopover() {
return (
<Popover.Root>
<Popover.Trigger>Открыть Popover</Popover.Trigger>
<Popover.Content>
<p>Неконтролируемый контент</p>
<Popover.Close>Закрыть</Popover.Close>
</Popover.Content>
</Popover.Root>
);
}
Radix UI компоненты не навязывают конкретную библиотеку для анимаций,
поэтому анимации можно интегрировать через useState и CSS
transition:
import * as Toast from '@radix-ui/react-toast';
import { useState } from 'react';
function AnimatedToast() {
const [open, setOpen] = useState(false);
return (
<>
<button onCl ick={() => setOpen(true)}>Показать уведомление</button>
<Toast.Root open={open} onOpenCha nge={setOpen} className="transition-all duration-300">
<Toast.Title>Успешно</Toast.Title>
<Toast.Description>Действие выполнено</Toast.Description>
<Toast.Close>Закрыть</Toast.Close>
</Toast.Root>
</>
);
}
Рекомендации по анимациям:
framer-motion можно подключать
напрямую к Radix компонентам для кастомного поведения.useContext с Radix UIRadix UI компоненты удобно использовать внутри React Context для передачи глобальных настроек. Например, для темы или локализации:
import * as Tabs from '@radix-ui/react-tabs';
import { createContext, useContext, useState } from 'react';
const TabsContext = createContext();
function TabsProvider({ children }) {
const [tab, setTab] = useState('tab1');
return <TabsContext.Provider value={{ tab, setTab }}>{children}</TabsContext.Provider>;
}
function CustomTabs() {
const { tab, setTab } = useContext(TabsContext);
return (
<Tabs.Root value={tab} onValueCha nge={setTab}>
<Tabs.List>
<Tabs.Trigger value="tab1">Вкладка 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Вкладка 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Контент 1</Tabs.Content>
<Tabs.Content value="tab2">Контент 2</Tabs.Content>
</Tabs.Root>
);
}
Использование useContext позволяет:
open и onOpenChange
для контролируемых компонентов.useId для
совместимости с SSR.Эти принципы делают использование Radix UI с React максимально гибким, доступным и предсказуемым, обеспечивая контроль над любым поведением компонента через Hooks.