skip to content
menu
patterns · selection and bulk actions

selection and bulk actions

In a long list, people often want to do the same thing to many items: grab eight episodes, restart three workloads, archive forty old items. Doing that one row at a time is slow, and easy to get wrong. So people first select the rows, by ticking their checkboxes, and then act on all of them at once, with a bulk action.

40 missingS04E01S04E02S04E03S04E04S04E05S04E063 selectedS04E01S04E02S04E03S04E04S04E05S04E0640 missingS04E01S04E02S04E03S04E04S04E05S04E063 episodes queued1 Tick the rows2 Press the action3 Read the result
Tick the rows, press the one blue button in the toolbar, and a short message counts what happened.

The data table and the selection toolbar do this; their pages show them live, and this pattern's React page has the whole thing to try.

when it fits

  • When people act on many rows the same way.
  • In a worklist, where the list is the work and its toolbar holds what to do with it.
  • When some rows can't take the action right now: they stay in the list, can't be ticked, and say why.

It isn't the right tool:

  • For one action on one row. Use the row's menu, or let a press open the row. People shouldn't have to select a row to act on it.
  • For choosing values in a form, like the volumes a backup includes. Use checkboxes or a multi select: a form's values are saved with the form, not acted on at once.
  • For narrowing a list. Use the filters. Selecting rows hides nothing.
  • For records nobody acts on. A short list to read needs no selection at all.

selection modes

Pick how a list selects by the actions it has, not by habit.

mode when what changes
None The list has no bulk actions Nothing: a press on a row opens it
Single A list next to the detail of the row that is chosen The chosen row is highlighted; there are no checkboxes
Multiple The list has actions that apply to several rows at once A column of checkboxes appears; nothing else changes

Today the data table does two of the three: none, and multiple. Single selection, a list beside its detail, is planned.

press versus select

Pressing a row and ticking it do different things, and people shouldn't have to wonder which one they are about to do.

S04E01missingS04E02missingS04E03missingThe checkbox selectsA press anywhere else opens the row
The checkbox selects. A press anywhere else on the row opens it, and the › at the row's end says that it will.
  • A press opens, the checkbox selects. No spot does both.
  • When a row has nothing to open, in a list with checkboxes, a press anywhere on it ticks its checkbox.

Today the data table keeps the two apart as described. The › at the end of a row that opens isn't drawn yet: it is planned.

anatomy

8 selectedclearselect all 37The Quiet Harbour · S04 · 9 missingS04E01missingS04E02missingS04E03missingS04E04missingS04E05on its wayS04E06missing8 episodes queued123456789
A list that selects, close up.
  1. The selection toolbar. It takes the place of the list's title bar. With nothing selected, it says what the list holds: “40 missing”. With a selection, it shows the count in blue, “8 selected”, a way to clear it, and, when it helps, “select all 37”.
  2. The emphasized action. The toolbar's one blue button, with the count in its label: “grab 8 selected”. It is only there while something is selected.
  3. Other actions. Quieter buttons, or items in the toolbar's “more” menu, which is always there when the toolbar is narrow.
  4. The select-all checkbox in the table's header. It selects every row on the screen.
  5. A checkbox on each row, named after the row: “select S04E07”. A selected row is tinted, with a blue bar on its edge.
  6. A menu on each row, at its end, named after the row: “actions for S04E07”.
  7. A group's row and its action. The group's name and count, and one small, quiet button that acts on the whole group: “grab all 9”.
  8. Rows that can't be selected. A greyed-out checkbox, and a status that says why: “on its way”.
  9. The confirmation. A toast that counts what happened: “8 episodes queued”.

select all

40 selectedselect all 2,409S04E01missingS04E02missingS04E03missing
After the header checkbox: the 40 rows on the screen are selected, and the toolbar offers all 2,409.
  • The header checkbox selects the rows that are loaded and match the filters. The toolbar then offers the rest, “select all 2,409”, and its count always says which of the two is in effect.
  • After select all, the count says exactly what will be acted on: “2,409 selected”, not just “all”. The button says the same number: “grab 2,409 selected”.
  • The header checkbox shows a dash while some rows are selected but not all, and a tick when all of them are. Pressing it while it shows a tick clears the selection.
  • Offering “select all 2,409” matters most right after the header checkbox. That is the moment people wonder whether they have only these rows, or all of them.

Today the header checkbox selects every row on the screen, but not the rows past “show more”, or in collapsed groups. The app decides when to offer “select all”.

the selection toolbar

  • It takes the title bar's place while something is selected, with the count, “clear”, and the actions. With nothing selected, it is the list's title bar again.
  • One emphasized action: the one people use most, labelled with a verb, what it acts on, and the count. The count keeps it honest: people check it before they press.
  • An action that only works for some of the selected rows stays available. It acts on those it can, and says what it skipped: “6 queued · 2 already on their way”.
  • An action that can be undone runs at once, without asking. One that deletes, or can't be undone, asks first, in a dialog with the count in its title and on its button.
do
8 selectedgrab 8 selected
A verb, what it acts on, and the count: people check the number before they press.
don't
8 selectedapply
Apply what, to how many? People have to remember what they selected.

per-row actions

  • One menu per row, at its end, with that row's actions: “grab now”, “search again”. Buttons on every row repeat the same labels all the way down, and bury the content.
  • Name the menu after its row. Grey out an item that doesn't apply to a row, rather than leaving it out, so every row's menu has the same shape.
  • A row's own action doesn't clear the selection. If it leaves its row unselectable, that row drops out of the selection.
do
S04E01missingS04E02missingS04E03missingS04E04missingS04E05missing
One small menu per row, named after the row.
don't
S04E01missinggrabreleasesS04E02missinggrabreleasesS04E03missinggrabreleasesS04E04missinggrabreleasesS04E05missinggrabreleases
Buttons on every row: the same labels again and again, and less room for the content.

group actions

  • A group's row can carry one action for the whole group, as a small, quiet button. A button like “grab all 9” acts on the rows of the season that can be grabbed, and its label counts them.
  • Leave the action out when it would act on nothing.
  • A group's action works without a selection, and pressing it doesn't tick the group.

after the action

  • Update the rows. Their status shows the new state, “on its way”. Keep the rows people just acted on in the list, unless the list is defined by the old state, like a “needs attention” tab; then say that they left.
  • Clear the selection the action used. The toolbar goes back to its title, and a screen reader hears “selection cleared”.
  • Confirm in a toast that counts what happened, and what didn't and why: “6 episodes queued · 2 skipped: on their way already”.
  • Count skipped rows; don't hide them. Rows get skipped when their state changed after they were selected, or when a service refuses some.
  • When the action fails, or partly fails and people need to do something, say so in a banner above the list, with a way forward, not in a toast. See message handling.
do
6 episodes queued · 2 skipped:on their way already
The toast counts what happened, and what was skipped and why.
don't
Done
Done says nothing about what was done, or what wasn't.

rows that can't be selected

  • Keep them in the list with a greyed-out checkbox, and say why in their status: “on its way”. Every way of selecting leaves them out, select all and ranges included.
  • Don't hide the checkbox or the row. People need to see that the row is there, and why it is left out.

keeping a selection

8 selected8 selected3 hidden by filtersseason 4
A filter hides three of the eight selected rows. They stay selected, and the toolbar says so.
  • Sorting, showing more and refreshing keep it.
  • Filtering keeps it too. Rows hidden by a filter stay selected, and the toolbar says so: “8 selected · 3 hidden by filters”.
  • Leaving the view clears it, and so does a finished bulk action, which says its result in a toast.

Today the data table keeps whatever selection the app gives it; keeping or clearing it is up to the app. Nothing counts the rows a filter hides yet; the toolbar can show that count when the app keeps it. The worklist's live example is older than this rule: it unselects a row as soon as a filter hides it.

keyboard

The toolbar is one stop for the Tab key, and the table's rows are another; the header's controls, select all and the sort buttons, are stops of their own in between. From a row, Tab goes on into its checkbox and its menu.

where key what it does
Table ↑ and ↓, Home and End, Page Up and Page Down Moves between rows
Table Space Ticks or unticks the row
Table Shift and a click, Shift+Space, Shift+↑ or Shift+↓ Selects a range, from the last row ticked
Table Ctrl+A or Cmd+A Selects every loaded row that matches the filters
Table Esc Clears the selection
Table Tab Goes into the row's checkbox and menu
Toolbar ← and →, Home and End Moves between the toolbar's controls, round and round
Row menu Enter, Space or ↓ Opens it on its first item; ↑ opens it on its last
Row menu Esc Closes it, and the focus goes back to its button

Today Ctrl+A or Cmd+A selects every row on the screen, like the header checkbox, and Esc doesn't clear the selection yet: it is planned.

accessibility

  • Names. Each checkbox: “select S04E07”. The header checkbox: “select every visible row”. Each menu: “actions for S04E07”. The toolbar: the list's name, “missing episodes”.
  • What is read out. The toolbar reads each change of the count once, politely: “8 selected”, “selection cleared”. The toast is read out too, and never takes the focus. The table says nothing about the selection as a whole; each row says whether it is selected.
  • Not by colour alone. The checkbox carries the selection; the row's tint and its blue bar only add to it.
  • The focus stays put when the button people pressed goes away. Pressing “clear”, “select all” or the bulk action removes that button; the toolbar then holds the focus itself. When a group's action disappears, or a focused row leaves the list, the focus moves to the table.

Today the header checkbox's name, and the word “select” before each row's label, are in English only.

the words

  • The count. “8 selected”, with thousands separators: “2,500 selected”.
  • The bulk action. A verb, what it acts on, and the count: “grab 8 selected”, “restart 3 workloads”. Not “ok”, “apply” or “submit”.
  • Select all. The number that will be selected: “select all 2,500”.
  • Hidden rows. The count after the selection: “8 selected · 3 hidden by filters”.
  • Clear. “clear”.
  • The toolbar's title. What the list holds: “2,500 missing”, “40 workloads”.
  • Row menu items. A verb for the one row: “grab now”, “search again”.
  • Group actions. The count they act on: “grab all 9”.
  • The toast. What happened, counted, in the items' own words, then what was skipped and why. Not “done”, “success” or “action completed”.
  • Why a row can't be selected. Its status, in the item's words: “on its way”, “held”. Not “disabled” or “n/a”.