Components

SwipeableItem

Headless swipe actions for list-like items.

When to Use

Use SwipeableItem when a list row has a few quick actions that touch users can reveal by swiping, while keyboard users can reveal the same actions with Arrow keys. Keep an obvious non-swipe path to important actions. Use a Menu when there are many actions or when a hidden swipe gesture would be surprising.

Features

  • Supports start and end action panels.
  • Supports pointer dragging and keyboard opening.
  • Supports controlled and uncontrolled open side state.
  • Supports left-to-right and right-to-left direction.
  • Supports optional full-swipe actions.
  • Closes open action panels after action clicks by default.
  • Supports asChild and render on every part.

Import

import { SwipeableItem } from "@flowstack-ui/atom";

Anatomy

<SwipeableItem.Root>
  <SwipeableItem.Actions side="start" />
  <SwipeableItem.Content />
  <SwipeableItem.Actions side="end" />
</SwipeableItem.Root>

API Reference

Root

Owns the open side, drag offset, direction, thresholds, and measured action widths shared by Content and Actions.

ARIA: Root adds no role or ARIA attributes.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
openSide"start" | "end" | null-
defaultOpenSide"start" | "end" | nullnull
onOpenSideChange(side: "start" | "end" | null) => void-
onFullSwipe(side: "start" | "end") => void-
disabledbooleanfalse
readOnlybooleanfalse
thresholdnumber0.35
fullSwipeThresholdnumber0.6
dir"ltr" | "rtl"Direction context
Data attributeValues
[data-slot]"swipeable-item"
[data-state]"open" | "closed"
[data-side]"start" | "end" when open
[data-dragging]Present while dragging
[data-disabled]Present when disabled
[data-readonly]Present when read-only
CSS variableDescription
--atom-swipeable-item-offsetCurrent content offset
--atom-swipeable-item-start-sizeMeasured start action width
--atom-swipeable-item-end-sizeMeasured end action width

Content

Renders the focusable row surface that interprets horizontal pointer movement and keyboard commands. It mirrors Root state and remains focusable when read-only.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
tabIndexnumber0
ARIA attributeValues
aria-disabledtrue when Root is disabled
Data attributeValues
[data-slot]"swipeable-item-content"
[data-state]"open" | "closed"
[data-side]"start" | "end" when open
[data-dragging]Present while dragging
[data-disabled]Present when disabled
[data-readonly]Present when read-only

Actions

Groups the controls revealed on one logical side. Closed panels are both aria-hidden and inert, so their controls cannot be reached accidentally.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
side"start" | "end"Required
aria-labelstring"<side> actions"
closeOnClickbooleantrue
ARIA attributeValues
role"group"
aria-labelExplicit label or "start actions" / "end actions"
aria-hiddentrue while the panel is closed
inertPresent while the panel is closed
Data attributeValues
[data-slot]"swipeable-item-actions"
[data-side]"start" | "end"
[data-state]"open" | "closed"

Advanced parts can use useSwipeableItemContext and its public provider. The exported side, size, offset, clamping, and direction helpers expose Root's direction-aware calculations.

Examples

Two-sided actions

import { SwipeableItem } from "@flowstack-ui/atom";

export default function MessageActions() {
  return (
<SwipeableItem.Root>
  <SwipeableItem.Actions side="start">
    <button type="button">Archive</button>
  </SwipeableItem.Actions>
  <SwipeableItem.Content>Email from Alex</SwipeableItem.Content>
  <SwipeableItem.Actions side="end">
    <button type="button">Delete</button>
  </SwipeableItem.Actions>
</SwipeableItem.Root>
  );
}

Full-swipe action

import { SwipeableItem } from "@flowstack-ui/atom";

export default function FullSwipeAction() {
  return (
<SwipeableItem.Root onFullSwipe={(side) => window.alert(`Full swipe: ${side}`)}>
  <SwipeableItem.Actions side="end">
    <button type="button">Delete</button>
  </SwipeableItem.Actions>
  <SwipeableItem.Content>Message</SwipeableItem.Content>
</SwipeableItem.Root>
  );
}

Accessibility

SwipeableItem provides equivalent pointer and keyboard operation rather than a special WAI-ARIA widget role. Content is keyboard focusable. Arrow keys open, close, and can full-swipe action panels when onFullSwipe is provided. Escape closes the item. Hidden action panels are removed from the accessibility tree and made inert until open.

KeyDescription
ArrowLeft / ArrowRightOpens a direction-aware action side. When a side is open, the opposite arrow closes it. Pressing the same arrow again triggers onFullSwipe when available.
EscapeCloses an open item.

Changelog

See CHANGELOG.md.