Components / Actions

SwipeActions

Reveal row actions with a swipe, or from the same actions in a menu.

Install

npx shadcn@latest add https://irisui.dev/r/swipe-actions.json
import { SwipeActions } from "@/components/iris/swipe-actions/swipe-actions";
Registry item swipe-actionsBrings in foundationRegistry JSON

Preview

SwipeActions

A list whose rows reveal actions with a horizontal swipe — a long swipe commits the outermost action — with the same actions always available from a More actions menu.

When to use

  • Touch-first lists with quick per-row triage: inbox messages, notifications, tasks (archive, snooze, mark unread).
  • When the row should collapse after the action (archive) or spring back (keepRow, for mark as unread).
  • On pointer-first, dense desktop tables, prefer visible row actions or ContextMenu; swipe is not discoverable with a mouse.

Usage

import { SwipeActions } from "@/components/iris/swipe-actions/swipe-actions";

<SwipeActions label="Inbox">
  {messages.map((message) => (
    <SwipeActionsRow
      key={message.id}
      label={message.subject}
      leading={[
        {
          label: "Unread",
          icon: <MailOpenIcon size={18} />,
          tone: "accent",
          keepRow: true,
          onSelect: () => markUnread(message.id),
        },
      ]}
      trailing={[
        { label: "Archive", icon: <ArchiveIcon size={18} />, tone: "danger", onSelect: () => archive(message.id) },
      ]}
    >
      <MessagePreview message={message} />
    </SwipeActionsRow>
  ))}
</SwipeActions>;

Props

SwipeActions

Prop Type Default Description
label string — Accessible name of the list (required).
children ReactNode — SwipeActionsRow elements (required).
className string — Extra class on the list surface.

SwipeActionsRow

Prop Type Default Description
label string — Names the row's More actions button (required), e.g. the message subject.
leading SwipeAction[] [] Actions revealed by swiping right.
trailing SwipeAction[] [] Actions revealed by swiping left.
fullSwipe boolean true Lets a long swipe commit the outermost action without a tap.
children ReactNode — Row content (required).

SwipeAction: { label, icon, onSelect, tone?: "neutral" | "accent" | "danger", keepRow? }. onSelect runs for a full swipe, a tap on the revealed action, or the menu — remove the item in it unless keepRow is set.

Notes

  • The revealed actions are aria-hidden and out of the tab order; the per-row More actions menu (Radix) is the accessible path for keyboard and screen-reader users.
  • Only one row is open at a time; a press outside or Escape closes it. Vertical drags are handed to the page as scroll.
  • Removing an item collapses its row; re-adding it (undo) slides it home. Reduced motion snaps travel instead of springing.
  • Pair danger tone with a label that names the destructive result.