Everything a pointer does, the keyboard does too: lift, move, change the level, change the column, drop, put back, select several, open and close, rename and pick. A screen reader hears each step.

Roles

  • A list is a listbox, its items options. With multiple, the list has aria-multiselectable and each item aria-selected; with on_select, too.
  • A tree is a tree, its items treeitems with aria-level, aria-posinset and aria-setsize among their siblings, and aria-expanded on the items with children. An item whose children are loading is aria-busy.
  • A board is a group. Each column is a section named by its header, and its cards are a listbox of options.
  • A tree picker is a tree whose items have aria-selected; the items that cannot be picked are aria-disabled.
  • label names the whole list, tree or board. Each item's name for the announcements is its label (item_label).

One item takes the Tab at a time (a roving tabindex): the focused one, else the first selected, else the first shown.

Keys

Key
↓ ↑the next, the previous item
Home, Endthe first, the last item
→a tree: open the item, or go to its first child; a board: the next column
←a tree: close the item, or go to its parent; a board: the previous column
Spacelift the item (and the others selected); in a picker, pick it
Enterin a picker, pick the item
Shift+↓ ↑extend the selection (multiple)
Ctrl+A, Cmd+Aselect all the items shown (multiple)
Escapeclear the selection
Ctrl+Shift+arrows, Cmd+Shift+arrowsmove the item one step, without lifting it
F2rename (on_rename)

While an item is lifted:

Key
↓ ↑the next, the previous gap
Home, Endthe first, the last gap
→ ←a tree: one level deeper, one level up; a board: the next, the previous column
Space, Enterdrop
Escapeput it back
Tabput it back, and move on

Focus that leaves the list puts a lifted item back. A list without on_move, or readonly, does not lift: Space toggles the selection with multiple.

Announcements

A live region says what happens, in the words of the list's locale:

  • "Roadmap lifted. Arrows move it, Space drops it, Escape puts it back."
  • "Roadmap, in Projects, 2 of 3" as it moves, and "Roadmap dropped, 2 of 3".
  • "Roadmap is back in its place" when it is put back.
  • Why a place is refused: "It can't go there: It would be nested too deep".
  • "The move was not saved, and is undone" when the server says no, with its reason.
  • How many items the filter shows, or "No matches"; how many are selected; a row opened or closed.

The words are in English, Portuguese, Spanish, French, German, Italian, Dutch and Japanese; numbers are formatted by the browser for the locale. A locale with a region (pt-BR) takes its language's words; another language gets English. messages changes words by the keys of Narabe.Messages.keys/0, and the config sets them for every list:

config :narabe, messages: %{"fr" => %{"dragHandle" => "Glisser pour déplacer"}}

The pointer and touch

A mouse lifts an item once it moves a few pixels, so a click stays a click. A finger lifts it after a short hold, so a swipe still scrolls the page; the phone vibrates briefly where it can. On a touch screen rows are 2.75rem tall. Escape during a drag lets go and nothing moves.

Motion and color

With prefers-reduced-motion, rows and arrows do not animate. A refused drop is shown by its red line and said in words: color is never the only sign.

Tested

mix test.e2e checks the roles, levels, focus and announcements in Chromium, Firefox and WebKit. Not tested yet: screen readers themselves (see Known limits).