Swipe actions
Usage
Use swipe actions on the mechanics' tablet and phone lists, where a row's two or three most frequent actions save a trip into the work order: mark it done, reassign it, delete a duplicate.
- Trailing swipe (toward the inline start) reveals up to three actions; the edge action is the one a full swipe runs.
- Leading swipe reveals one positive action (Mark done).
- Always put the same actions in the row's More actions menu. A swipe is a shortcut, never the only way (WCAG 2.5.7), and desktop dispatchers never swipe.
- Don't hide an action people need to discover (put it in the menu or on the detail page), or use a full swipe for something that can't be undone without an Undo toast.
Content: one or two words per action, a verb ("Reassign", "Delete"). The destructive action says what it does in the menu ("Delete work order").
Anatomy
- Row —
<li class="swipe-row">with--_leadand--_trailaction counts - Track —
.swipe-row__track, the horizontal scroll-snap container - Leading actions —
.swipe-row__actions--leading,inertuntil revealed - Content —
.swipe-row__content: link (stretched over the row), secondary text and the More actions menu button - Trailing actions —
.swipe-row__actions--trailing, edge action last; its color fills the full-swipe zone
Examples
Revealed and full-swipe states are frozen with docs-only classes; the first demo is live on touch screens.
Swipe actions
At rest only the content shows. On a touch screen swipe a row left for Reassign and Delete, right for Mark done; with a mouse or keyboard use the More actions button.
Swiped toward the inline start: trailing actions are revealed and focusable. Tapping the content closes the row.
Swiped toward the inline end: the leading action (Mark done) is revealed.
Swiped past half the trailing zone: the edge action (Delete) covers the row and runs on release. The row is removed with an Undo toast.
Keyboard focus on the row's link: the ring sits inside the row so the next row doesn't cover it.
The same actions in the row's menu button: the required non-swipe path, and the only one with a mouse.
<ul class="list-group swipe-list" role="list" aria-label="Work orders">
<li class="swipe-row" style="--_lead: 1; --_trail: 2">
<div class="swipe-row__track">
<div class="swipe-row__actions swipe-row__actions--leading" inert>
<button type="button" class="swipe-row__action swipe-row__action--primary">Mark done</button>
</div>
<div class="swipe-row__content">
<div class="swipe-row__main"><a class="swipe-row__link" href="/work-orders/4182">WO-4182 Brake inspection</a>
<span class="swipe-row__secondary">Van KX-219 · Northside Depot</span></div>
<button type="button" class="icon-btn swipe-row__menu" aria-haspopup="menu" aria-controls="wo-4182-menu"
commandfor="wo-4182-menu" command="toggle-popover" aria-label="More actions for WO-4182 Brake inspection">…</button>
<div class="menu" id="wo-4182-menu" popover role="menu">Mark done · Reassign · Delete work order</div>
</div>
<div class="swipe-row__actions swipe-row__actions--trailing" inert>
<button type="button" class="swipe-row__action">Reassign</button>
<button type="button" class="swipe-row__action swipe-row__action--danger">Delete</button>
</div>
</div>
</li>
</ul>
<script type="module">import { init } from "./js/swipe-actions.js"; init();</script>
API
| Hook | Values | Purpose |
|---|---|---|
.swipe-row | block | One row; --_lead / --_trail = number of leading / trailing actions |
.swipe-row__action--primary | --danger | modifier | Action color; the trailing edge action (last) sets the full-swipe color |
.swipe-list | modifier on .list-group | Clips revealed actions to the list's rounded frame |
js/swipe-actions.js init(root) | module | Rest position, inert sync, one open row, tap-to-close, full swipe (.is-full) |
.is-revealed-trailing | -leading | .is-full-swipe | .is-focus-visible | docs-only class | Freeze a state for documentation and snapshots |
Do and don't
Swipe for Reassign and Delete, and the same three actions in the row's menu.
Delete only by swiping, with no Undo.
Accessibility
| Key | Behavior |
|---|---|
| Tab | Row link, then the More actions button. Hidden swipe actions are inert and skipped |
| Enter / Space on More actions | Opens the menu with the same actions (APG menu button) |
- Pointer gestures and dragging (WCAG 2.5.1, 2.5.7): every swipe action is also a menu item reachable with one tap or click.
- Pointer cancellation (2.5.2): nothing runs while swiping; a full swipe runs only when the row settles past the threshold, and moving back cancels it.
- Names: action buttons have visible text; the menu button's name includes the row ("More actions for WO-4182 Brake inspection").
- Deleting a row moves focus to the next row's link and announces "Work order deleted" with an Undo button in a toast.
- Reduced motion: rows close without smooth scrolling. RTL: leading and trailing flip with the writing direction.
- Forced colors: action buttons keep a
ButtonTextborder; the focus ring usesHighlight.
Tokens
| Custom property | Purpose |
|---|---|
--size-swipe-action | Width of each action (mobile scope token, same on native) |
--size-touch-target | Minimum row and action height |
--color-action-{primary|secondary|danger}-{bg|fg} | Action colors |
--color-elevation-surface-raised | Row content surface |
--color-border-subtle | Separator between rows |
--focus-ring-width, --focus-ring-color | Inset focus ring |