Swipeable Item
Primitive

Swipeable Item

Headless swipe actions for list-like items.

Live behavior

Swipeable Item in motion

Interactive
Atom behavior · App-owned appearance
Preparing behavior…

Swipe the row or use its keyboard-safe visible action.

waiting for input

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

The behavior Atom owns before your product adds appearance.

  • Supports start and end action panels.
  • Supports pointer dragging and keyboard opening.
  • Preserves native vertical panning with an axis-compatible touch policy.
  • 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

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

Anatomy

tsx
<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. Atom applies touch-action: pan-y so vertical document or scroll-container panning remains native. An authored style.touchAction can override that default deliberately. Arrow-key reveal runs only while Content itself is the keyboard target; interactive descendants retain their own Arrow behavior.

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

tsx
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

tsx
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.

Swipe must remain an enhancement. Provide an obvious tap/click path to every command, such as a visible overflow-menu trigger or persistent action. Keyboard support alone is not the required single-pointer alternative to dragging.

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

Unreleased

0.24.0

  • Added source-led Agent Knowledge for gesture-enhanced row actions, required non-swipe fallbacks, pointer and scroll behavior, keyboard isolation, logical direction, and action accessibility.

0.19.9

  • Preserved native vertical panning with an axis-compatible Content touch policy and stopped bubbled Arrow keys from nested controls from revealing action panels.
  • Added real-browser and numbered manual evidence for gesture settlement, cancellation, keyboard isolation, logical direction, and scrolling.

0.2.0

  • Added closeOnClick to SwipeableItem.Actions, defaulting to closing the open item after an action click.
  • Updated keyboard handling so the opposite arrow closes an open side and the same arrow can trigger onFullSwipe.
  • Allowed drag travel to full content width even when no full-swipe callback is configured; release still settles using the configured threshold.

0.1.0

  • Initial Atom release.