Every gesture needs a button

Every drag, swipe or slide also needs a click and a keyboard path.

Vercel Labsweb-interface-guidelines · Touch & Drag
Drag/swipe/pinch/path gestures need tap/click and keyboard alternatives unless essential
command.mdView source ↗
Vercel Labsweb-interface-guidelines · Anti-patterns
Gesture-only action without tap/click and keyboard alternative
command.mdView source ↗

From web-design-guidelines. Related: WCAG 2.5.7 Dragging Movements ↗.

Swipe to delete

Swipe a row left, then try again keyboard only.

Swipe onlyBad
    Swipe, or menuGood
      function remove(row) {
        const next = row.nextElementSibling ?? row.previousElementSibling;
        row.remove();
        next?.querySelector(".more").focus();
      }
      swipe.onCommit = remove;
      menu.onDelete = remove;

      Drag to reorder

      Add a task, then move it to the top.

      Drag onlyBad
        Drag, buttons, keysGood

          Alt plus Up or Down arrow moves this task.

          row.onkeydown = (e) => {
            if (e.altKey && e.key === "ArrowUp") move(row, -1);
            if (e.altKey && e.key === "ArrowDown") move(row, 1);
          };
          upButton.onclick = () => move(row, -1);

          Slide to confirm

          Pay with each slider, then raise the distance.

          Path gesture onlyBad
          Slide to pay $1,240.00
          Slide, tap twice, keysGood

          Arrow keys or End to slide. Or press Enter twice.

          <div role="slider" tabindex="0" aria-label="Slide to pay"
               aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"></div>

          Why it matters, pros and cons

          Why it matters

          Keyboard and screen-reader users can't trace a path; a button can.

          Pros

          • Meets WCAG 2.1.1, 2.5.1 and 2.5.7.
          • A visible button shows the action exists.
          • One code path for every input.

          Cons

          • More chrome per row; one menu keeps it small.
          • Key bindings are invisible; announce moves via aria-live.
          • Exempt only when the path is the input, like signatures.