suiss/ui · Interaction
Swipe Actions
A list row that reveals action buttons when swiped sideways, with optional full swipe to run an action.
Swipe Actions is an open-source interaction from suiss/ui for React, React Native, SwiftUI and Jetpack Compose. The @esuiss/ui CLI copies its source into your project, so you own the code.
SwipeActions recreates iOS swipe actions for list rows. Dragging SwipeActionsContent sideways reveals the buttons in SwipeActionsActions on that side; releasing past half their width snaps the row open, otherwise it springs closed. Dragging past the actions meets increasing resistance, unless an action has fullSwipe: then dragging past 60% of the row width expands that action across the row, and releasing collapses the row and runs it.
Only one row stays open at a time. Tapping the content or pressing elsewhere closes an open row, and choosing an action closes it after the action runs. Use it for quick per-row actions such as archive, delete, or mark as unread.
Installation
CLI
Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:
Manual
- Install the dependencies and add the
cnhelper:
- Copy the source into
components/interactions/swipe-actions.tsx:
- Update the import paths to match your project.
Usage
- Place
SwipeActionsContentinsideSwipeActions, with aSwipeActionsActionsfor each side that has actions. Rows can have leading actions, trailing actions, or both. - Handle each action with
onClick. A full swipe runs the action by clicking it, so the same handler covers both. useSwipeActionsreturnsclosefor closing the row from custom controls.- Gestures are detected with pointer events and locked to the horizontal axis after a few pixels, so vertical scrolling still works.
Examples
Both sides
A row with a leading Unread action on one side and trailing Archive and Delete actions on the other.
Variants
The default, neutral, archive, and destructive action colors side by side.
API Reference
SwipeActions
The row container that tracks the swipe and manages open state.
Also accepts the props of React.ComponentProps<"div">.
SwipeActionsContent
The visible row content that moves with the swipe.
Also accepts the props of React.ComponentProps<"div">.
SwipeActionsActions
The group of actions revealed on one side of the row.
| Prop | Type | Default | Description |
|---|---|---|---|
side | SwipeActionsSide | "trailing" | The edge the actions appear on: leading or trailing. |
Also accepts the props of React.ComponentProps<"div">.
SwipeAction
A single action button revealed by the swipe.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "destructive" | "archive" | "neutral" | "default" | The background color of the action: default, destructive, archive, or neutral. |
fullSwipe | boolean | false | Lets a long swipe expand this action across the row and run it. |
Also accepts the props of React.ComponentProps<"button">.
Accessibility
- The row has
role="group", and actions are native buttons that stay in the tab order. - Moving focus to an action opens its side of the row so the button is visible; moving focus out of the row closes it.
Escapecloses an open row.- Leading and trailing sides follow the writing direction, so swipes mirror in right-to-left layouts.
Notes
- The root uses
data-slot="swipe-actions"and setsdata-open(leadingortrailing),data-fullduring a full swipe, anddata-removingwhile the row collapses. Action groups exposedata-side, and full-swipe actions setdata-full-swipe. - The
--swipe-actions-offsetcustom property holds the current offset. swipeActionVariantsis exported for styling other elements like an action.

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
The CLI also adds what it builds on: Icon, Text. On React Native it also adds the animated view components/ui/animated-view.tsx.
Manual
- Install the dependencies:
-
Add the pieces it builds on: Icon, Text, and the primitives
components/primitives/haptics.tsx, and the animated viewcomponents/ui/animated-view.tsxfrom the next step. -
Copy the animated view into
components/ui/animated-view.tsx:
- Copy the source into
components/interactions/swipe-actions.tsx:
- Update the import paths to match your project.
- Install the dependencies:
-
Add the pieces it builds on: Icon, Text, and the primitives
components/primitives/haptics.tsx, and the animated viewcomponents/ui/animated-view.tsxfrom the next step. -
Copy the animated view into
components/ui/animated-view.tsx:
- Copy the source into
components/interactions/swipe-actions.tsx:
- Update the import paths to match your project.
- Install the dependencies:
-
Add the pieces it builds on: Icon, Text, and the primitives
components/primitives/haptics.tsx, and the animated viewcomponents/ui/animated-view.tsxfrom the next step. -
Copy the animated view into
components/ui/animated-view.tsx:
- Copy the source into
components/interactions/swipe-actions.tsx:
- Update the import paths to match your project.
-
Target iOS 17 or later.
-
Copy the theme files every view uses:
- Copy the source and every file it uses:
- Add the files to your app target.
- Set
minSdkto 24 or higher and add the dependencies:
- Copy the theme files every view uses:
- Copy the source and every file it uses:
- Update the
com.esuiss.uipackage names to match your project.
Usage
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.
| Prop | Type | Default | Description |
|---|---|---|---|
onOpenChange | (side: SwipeActionsSide | null) => void | - | Called with leading, trailing or null when the row opens or closes. |
Also accepts the props of ViewProps.
SwipeActionsContent
The row content that slides.
Also accepts the props of ViewProps.
SwipeActionsActions
The group of actions for one side.
| Prop | Type | Default | Description |
|---|---|---|---|
side | SwipeActionsSide | - | leading or trailing. Defaults to trailing. |
children | React.ReactNode | - |
Also accepts the props of ViewProps.
SwipeAction
One action button.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "destructive" | "archive" | "neutral" | "default" | Background color of the action. |
fullSwipe | boolean | false | Runs the action when the row is swiped all the way. |
onPress | () => void | - | Called when the action is pressed or fully swiped. |
Also accepts the props of SwipeActionProps.
Accessibility
- Every action is offered as an accessibility action on
SwipeActionsContent, labelled by itsaccessibilityLabelor 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
grouprole and each action thebuttonrole.
Notes
- The full-swipe haptic plays only if the app provides an adapter through
HapticsProvider. - Action colors use
bg-primary,bg-destructive,bg-purple-500andbg-zinc-500withtext-primary-foregroundlabels and icons; the content usesbg-background.
