Swipe actions
Reveal row actions with a swipe, or from the same actions in a menu.
import { SwipeActions, SwipeActionsRow } from "@/forma/arc/swipe-actions/swipe-actions";Base
In FORMA
- Liegt in
kit/arc/swipe-actionsund ist über@/forma/arc/swipe-actions/swipe-actionserreichbar. - Farbe, Ecken, Höhen, Abstände, Tiefe, Schrift und Tempo kommen aus der Richtung (
core/arc-bridge.ts); Arc behält Verhalten, Tastatur und Federn.
When to use
- Touch-first triage lists such as mail, notifications, or tasks.
- Rows with one or two quick actions per side, like Archive and Mark unread.
- Lists where a full swipe should commit the main action and the row should animate away.
When not to use
- Use context-menu or dropdown-menu for desktop-first tables.
- Use reorderable-list when rows need to be dragged vertically.
- Use hold-to-confirm for a single destructive action outside a list.
Usage
import { SwipeActions, SwipeActionsRow } from "@/forma/arc/swipe-actions/swipe-actions";
import { Archive, MailOpen } from "@/forma/icons";
export function Inbox({ messages }: { messages: Message[] }) {
return (
<SwipeActions label="Inbox">
{messages.map(message => (
<SwipeActionsRow
key={message.id}
label={message.subject}
leading={[{ label: "Unread", icon: <MailOpen size={18} />, tone: "accent", keepRow: true, onSelect: () => markUnread(message.id) }]}
trailing={[{ label: "Archive", icon: <Archive size={18} />, tone: "danger", onSelect: () => archive(message.id) }]}
>
<MessagePreview message={message} />
</SwipeActionsRow>
))}
</SwipeActions>
);
}API reference
SwipeActions
The list. Keeps one row open at a time and closes it on an outside press or Escape.
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | – | Accessible name for the list. |
children (required) | ReactNode | – | SwipeActionsRow elements. Removing one animates its height closed. |
className | string | – | Extra class on the surface. |
SwipeActionsRow
One row whose actions reveal under its left and right edges on a horizontal swipe.
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | – | Names the row's More actions button, for example the message subject. |
leading | SwipeAction[] | [] | Actions under the left edge, revealed by swiping right. The first one commits on a full swipe. |
trailing | SwipeAction[] | [] | Actions under the right edge, revealed by swiping left. The last one commits on a full swipe. |
fullSwipe | boolean | true | Lets a long swipe or flick commit the outermost action. |
children (required) | ReactNode | – | Row content. |
className | string | – | Extra class on the row. |
SwipeAction
One action in leading or trailing.
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | – | Shown under the icon and in the menu. |
icon (required) | ReactNode | – | Action icon. |
onSelect (required) | () => void | – | Runs on full swipe, tap, or menu choice. Remove the item here unless keepRow is set. |
tone | "neutral" | "accent" | "danger" | "neutral" | Fill of the revealed action. |
keepRow | boolean | – | Springs the row home after the action instead of sliding it away. |
Keyboard interactions
| Keys | Action |
|---|---|
| Enter / Space | Opens a row's More actions menu from its button. |
| ArrowDown / ArrowUp | Moves between the row's actions in the menu. |
| Escape | Closes the menu or puts away an open row. |
Accessibility
- The list is a ul with role="list" and aria-label; each row is an li.
- Every row has a "More actions for <label>" menu with the same actions, so the gesture is never required.
- Revealed action buttons are aria-hidden and out of the tab order; after a removing action, focus moves to a neighbouring row.
Motion
- The row tracks the finger, rubber-bands past its last stop, and settles on a spring that carries the release velocity; a flick projects its travel.
- Past the threshold the outer action stretches across the row, then the row slides out and the list closes the gap.
- Reduced motion jumps the row to its stops and fades rows in and out instead of animating height.
Responsive behavior
- Swipes lock to the horizontal axis after the first movement, so vertical page scrolling still works on touch.
- A full swipe commits past the larger of the open width plus 48px or 56% of the row, measured with a ResizeObserver.
- Every row also has a More actions menu, so mouse and keyboard users never need the gesture.
Performance
- Drag updates a motion value directly, so rows do not re-render while following the finger.
- Rows are not virtualized and each has its own ResizeObserver; paginate long lists.
Notes for AI
- Use for short, triage-style lists on touch (mail, notifications, tasks). For desktop-first tables use context-menu or a row menu.
- Remove the item from state inside onSelect; set keepRow for actions that keep the item, such as mark as unread.
- Rows must be direct children of SwipeActions, keyed by item id, so removal and undo animate.
Also in gestures
- Reactions: Acknowledge a post in one tap, with counts that roll.
Guidance for AI tools
Swipe actions: Reveal row actions with a swipe, or from the same actions in a menu. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.
Full library index: https://uiarc.dev/llms.txt
Komponente und Text: Arc UI (MIT, uiarc.dev), angepasst für FORMA.