Swipe для закрытия

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

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


Структура компонента Swipe

Radix UI разделяет функциональность Swipe на несколько подкомпонентов:

  1. <Swipe.Root> – контейнер для всего свайп-элемента. Управляет состоянием и настройками жеста.
  2. <Swipe.Viewport> – видимая область, в которой происходит свайп. Позволяет ограничить движение элемента.
  3. <Swipe.Item> – отдельный элемент, который можно свайпать.
  4. <Swipe.Content> – содержимое элемента, отображаемое пользователю.
  5. <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 для оптимизации производительности.

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

Свайп-компоненты можно связать с состоянием через хуки 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 можно применять не только в списках, но и для модальных окон, карточек и панелей:

<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>
  • Пользователь может закрывать модальные окна свайпом, улучшая UX на мобильных устройствах.
  • Сочетание с CSS-переходами позволяет реализовать эффект «сдвига и исчезновения» без сторонних библиотек анимации.

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

  • Для списков с большим количеством элементов рекомендуется использовать React.memo или виртуализацию.
  • Ограничение количества рендеров onOpen и onClose предотвращает лишние обновления состояния.
  • Минимизировать использование тяжелых анимаций внутри свайп-контента, чтобы избежать задержек на мобильных устройствах.

Советы по UX и дизайну

  • Устанавливать порог threshold в диапазоне 0.3–0.5 обеспечивает комфортное взаимодействие.
  • Добавлять визуальные индикаторы действия (например, иконку удаления), которые проявляются по мере свайпа.
  • Поддерживать обратную связь через цветовые переходы или небольшие вибрации на мобильных устройствах.

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