Skip to content

ExpressiveCSS

Browse documentation

Swipe actions

Reveals a list row's actions when a person swipes it sideways, or presses its actions button.

View as Markdown

Add swipeable to a list so people can swipe a row sideways on a touch screen to reach its actions. Each row's actions button does the same for everyone else.

A row with actions holds a <button data-swipe-toggle> as its trailing action, then a .swipe-actions group of buttons as its last child. AutoInit() starts every .list.swipeable. A touch swipe toward the row's inline start slides the row with the finger and brings the actions in from the other edge. Released past half the actions' width, or with a flick, the row stays open. A swipe only reveals the actions; none of them runs until a person presses it. On a touch screen, swipe a row below to the left; elsewhere, press its actions button.

  • Build passed on main
  • Invoice 2041 is ready
  • Design review moved to Thursday
  • New comment on the roadmap
  • Your export finished
<ul class="list swipeable" aria-label="Inbox">
  <li>
    <span class="material-symbols" aria-hidden="true">mail</span>
    Weekly report
    <button type="button" class="icon-button" data-swipe-toggle aria-label="Actions for Weekly report">
      <span class="material-symbols" aria-hidden="true">more_horiz</span>
    </button>
    <span class="swipe-actions">
      <button type="button" class="icon-button" aria-label="Archive Weekly report">
        <span class="material-symbols" aria-hidden="true">archive</span>
      </button>
      <button type="button" class="icon-button" aria-label="Delete Weekly report">
        <span class="material-symbols" aria-hidden="true">delete</span>
      </button>
    </span>
  </li>
</ul>

Without a swipe

Swiping needs a touch screen, so every row with actions needs its <button data-swipe-toggle>. Keyboard, mouse and switch users open and close the row with it, the script keeps its aria-expanded in step, and a semantics rule flags a row without one. Name the toggle and each action for the row they belong to.

The actions stay in the tab order and the accessibility tree while the row is closed, and focus on one opens its row, so tabbing reaches every action. A mouse drag never swipes, and neither does a drag that moves up or down first, which scrolls as usual.

Closing a row

One row in a list is open at a time. A tap or focus outside the open row closes it, as does a swipe the other way, or Escape inside it. Escape on an action, or pressing an action, closes the row and moves focus from the action to the toggle. The page handles what each action does. Under reduced motion the row still follows the finger but opens and closes without sliding. In a right-to-left page the actions sit at the left, and a swipe to the right reveals them.

Events

Opening or closing a row fires expressive:swipetoggle from the list and runs the onToggle option, both with { row, open }.

document.addEventListener('expressive:swipetoggle', (event) => {
  const { row, open } = event.detail;
  console.log(row, open ? 'opened' : 'closed');
});

Options

Name Type Default Description
onToggle Function null Called when a row opens or closes, with { row, open }.

Methods

const list = Expressive.SwipeActions.getInstance(document.querySelector('.list.swipeable'));
list.open(row); // opens a row of the list, closing the one that was open
list.close();   // closes the open row
list.destroy(); // removes listeners, closes the open row without an event

Tokens

Override these on the .list.swipeable.

Token Default
--md-comp-swipe-actions-gap4px
--md-comp-swipe-actions-motiondefault spatial spring
--md-comp-swipe-actions-motion-durationthe default spatial spring's duration

No matching pages

  • Source color

    The seed every generated ramp derives from. Pick one and browse the docs — the whole theme follows. Error does not: it is a fixed hue.

    Default source: Mist Iris.

    ExpressiveCSS presets: Lagoon, Harbor, Breeze, Cobalt, Iris.

    Bold

    Soft

    Mist

    Glow