How to build an accessible SwipeItem in React
The action buttons are always rendered in the DOM and the accessibility tree, never gesture-only. Focusing an action (via keyboard) reveals its side so it is visible, Enter/Space activate it, and Escape closes the row — giving full keyboard and screen-reader parity with the swipe gesture. The drag uses touch-action: pan-y so vertical scrolling is unaffected.
When to use a SwipeItem
- List rows on touch surfaces where secondary actions (archive, delete) should hide until swiped
- Mail/inbox-style rows that reveal contextual actions behind the content
- Compact lists where always-visible action buttons would crowd each row
When not to use it
- A single primary action per row — render it inline as a Button
- Destructive actions that need confirmation — pair with an AlertDialog instead of swipe-only
- Non-list, free-form content — swipe-to-reveal is a list-row affordance
Keyboard interactions
Role group, verified at WCAG 2.2-AA.
TabEnterSpaceEscape
Common mistakes
Avoid: Relying on the swipe gesture as the only way to reach Delete
Prefer: Action buttons stay in the DOM and a11y tree; focusing one reveals its side
Gesture-only actions are unreachable by keyboard and screen-reader users
Example
<SwipeItem
trailingActions={[
{ label: 'Archive', onSelect: archive },
{ label: 'Delete', onSelect: remove, destructive: true },
]}
>
<MessageRow message={message} />
</SwipeItem>