Radix UI предоставляет готовые компоненты с высокой степенью кастомизации для создания интерактивного пользовательского интерфейса. Одним из таких компонентов является Swipe, который позволяет реализовать функционал закрытия элементов свайпом, аналогично нативным мобильным приложениям.
Компонент Swipe особенно полезен для списков уведомлений, карточек с контентом и модальных элементов, где требуется интуитивное жестовое взаимодействие.
Radix UI разделяет функциональность Swipe на несколько подкомпонентов:
<Swipe.Root> – контейнер для
всего свайп-элемента. Управляет состоянием и настройками жеста.<Swipe.Viewport> – видимая
область, в которой происходит свайп. Позволяет ограничить движение
элемента.<Swipe.Item> – отдельный
элемент, который можно свайпать.<Swipe.Content> – содержимое
элемента, отображаемое пользователю.<Swipe.Action> – действие,
выполняемое после свайпа (например, удаление элемента).Пример базовой структуры:
import * as Swipe from '@radix-ui/react-swipeable';
<Swipe.Root>
<Swipe.Viewport>
<Swipe.Item>
<Swipe.Content>
Текст элемента
</Swipe.Content>
<Swipe.Action onAct ion={() => console.log('Элемент удалён')}>
Удалить
</Swipe.Action>
</Swipe.Item>
</Swipe.Viewport>
</Swipe.Root>
Для управления поведением свайпа доступны ключевые свойства на
<Swipe.Item>:
threshold – процент ширины, который
необходимо пройти элементу для срабатывания действия. Значение от
0 до 1.onOpen / onClose –
колбэки при завершении свайпа в открытое или закрытое состояние.stayOpen – логическая настройка,
определяющая, остаётся ли элемент открытым после свайпа.Пример с кастомным порогом:
<Swipe.Item threshold={0.3} onO pen={() => console.log('Открыт')}>
<Swipe.Content>
Контент карточки
</Swipe.Content>
<Swipe.Action onAct ion={() => console.log('Удаление')}>
Удалить
</Swipe.Action>
</Swipe.Item>
Radix UI позволяет гибко настраивать анимацию свайпа через CSS и Tailwind или любую другую CSS-библиотеку:
.swipe-content {
transition: transform 0.25s ease;
}
.swipe-action {
opacity: 0;
transition: opacity 0.2s ease;
}
.swipe-item[data-state='open'] .swipe-action {
opacity: 1;
}
data-state позволяет применять разные
стили в зависимости от состояния элемента.При интеграции свайп-компонентов в динамические списки необходимо учитывать ключи элементов для корректного рендеринга:
{notifications.map(notification => (
<Swipe.Item key={notification.id} threshold={0.5}>
<Swipe.Content>{notification.text}</Swipe.Content>
<Swipe.Action onAct ion={() => removeNotification(notification.id)}>
Удалить
</Swipe.Action>
</Swipe.Item>
))}
key гарантирует корректное удаление элементов без
нарушения состояния других компонентов.react-virtual для оптимизации
производительности.Свайп-компоненты можно связать с состоянием через хуки
useState или useReducer для управления
открытием и закрытием элементов:
const [openItems, setOpenItems] = useState({});
const handleOpen = (id) => setOpenItems(prev => ({ ...prev, [id]: true }));
const handleClose = (id) => setOpenItems(prev => ({ ...prev, [id]: false }));
<Swipe.Item
threshold={0.4}
onO pen={() => handleOpen(notification.id)}
onCl ose={() => handleClose(notification.id)}
>
<Swipe.Content>{notification.text}</Swipe.Content>
<Swipe.Action onAct ion={() => removeNotification(notification.id)}>
Удалить
</Swipe.Action>
</Swipe.Item>
Swipe можно применять не только в списках, но и для модальных окон, карточек и панелей:
<Swipe.Root>
<Swipe.Item threshold={0.25}>
<Swipe.Content className="modal">
Содержимое модального окна
</Swipe.Content>
<Swipe.Action onAct ion={() => setModalOpen(false)}>
Закрыть
</Swipe.Action>
</Swipe.Item>
</Swipe.Root>
React.memo или виртуализацию.onOpen и
onClose предотвращает лишние обновления состояния.threshold в диапазоне
0.3–0.5 обеспечивает комфортное взаимодействие.Radix UI Swipe сочетает удобство жестового управления и гибкость кастомизации, позволяя создавать интерфейсы с естественным поведением свайпов и высоким уровнем контроля над визуальной и функциональной частью элементов.