suiss/uim · Interaction

Swipe Actions

Swipe a list row sideways to reveal action buttons, with full swipe to run the main action.

Swipe Actions is an open-source mobile interaction from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Swipe Actions on iOS in light mode

SwipeActions wraps a row so it can be dragged left or right to reveal SwipeAction buttons on the leading or trailing side. The buttons stretch to fill the revealed space, and opening one row closes any other open row.

When an action has fullSwipe, dragging past 60% of the row width expands that action over the others with a medium impact haptic. Releasing there slides the row off, collapses its height, then runs the action, which suits delete or archive. Use it for mail, message or task lists.

Installation

$ pnpm dlx @esuiss/uim@latest add swipe-actions

The CLI also adds what it builds on: Icon, Text.

Manual

  1. Install the dependencies:
npx expo install class-variance-authority cn react-native-gesture-handler react-native-reanimated react-native-worklets
  1. Add the pieces it builds on: Icon, Text, and the primitives components/primitives/haptics.tsx.

  2. Copy the source into components/interactions/swipe-actions.tsx:

uniwind/components/interactions/swipe-actions.tsx
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "cn"
import * as React from "react"
import {
  type AccessibilityActionEvent,
  I18nManager,
  Pressable,
  View,
  type ViewProps,
} from "react-native"
import ReanimatedSwipeable, {
  type SwipeableMethods,
} from "react-native-gesture-handler/ReanimatedSwipeable"
import {
  Easing,
  runOnJS,
  1. Update the import paths to match your project.

Usage

import { SwipeActions, SwipeActionsContent, SwipeActionsActions, SwipeAction } from "@/components/interactions/swipe-actions"
<View>
  <Inbox />
</View>

Put the row in SwipeActionsContent, and the buttons in one SwipeActionsActions per side, with side set to leading or trailing (the default). Leading actions are on the left in left-to-right layouts and on the right in right-to-left layouts.

Pressing an action runs onPress and closes the row. For a full-swipe action, onPress runs after the row collapses, so remove the item from your data there. useSwipeActions returns close for closing the row from inside it. swipeActionVariants is also exported.

API Reference

SwipeActions

The root that handles the swipe gesture.

ExtendsViewProps
PropType
About
Called with leading, trailing or null when the row opens or closes.
Type
(side: SwipeActionsSide | null) => void
Default
—

SwipeActionsContent

The row content that slides.

ExtendsViewProps

SwipeActionsActions

The group of actions for one side.

ExtendsViewProps
PropType
About
leading or trailing. Defaults to trailing.
Type
SwipeActionsSide
Default
—
Type
React.ReactNode
Default
—

SwipeAction

One action button.

ExtendsSwipeActionProps

Accessibility

  • Every action is offered as an accessibility action on SwipeActionsContent, labelled by its accessibilityLabel or text, so screen reader users can run it without swiping.
  • Hidden actions are removed from the accessibility tree until their side is open.
  • The row has the group role and each action the button role.

Notes

  • The full-swipe haptic plays only if the app provides an adapter through HapticsProvider.
  • Action colors use bg-accent, bg-danger, bg-purple and bg-gray with text-on-accent labels and icons; the content uses bg-surface.