Skip to main content
Exemplar page — first pass. This is a proposal for review, not established policy. No Titan design-library review or shipped Invoca screen backs this page — it is built from general interaction-design practice and from constraints Table, List, and Checkbox already establish. Two of those constraints are real, current limits on what this pattern can promise, not workarounds this page invents around them:
  • TITAN-GAP-04background-hover and background-selected resolve to the identical color today. A hovered row and a selected row look the same, so this pattern cannot rely on fill color to show selection (see TITAN-DIV-20).
  • TITAN-GAP-33 — no indeterminate/mixed checkbox state exists in the design library. A select-all checkbox has no way to show “some, but not all.” This page does not invent one.

The problem

A reader looking at a table of a hundred campaigns doesn’t want to delete, export, or tag them one at a time. They want to check the ones they mean and act on all of them at once. Without a deliberate pattern for this, every team either repeats a row of action buttons on every row — expensive to scan and expensive to click fifty times — or bolts a bespoke selection model onto whichever table needed it first. Selection is also where ambiguity becomes expensive. “Select all” over a table sitting behind an active filter has at least three plausible meanings: every row on the current page, every row matching the filter, or every row that exists. Get the scope wrong on an export and the reader gets a stale file. Get it wrong on a delete and the reader loses data that was never on screen. This pattern is not the checkbox. The pattern is the bar that appears once something is selected, and the rule for what “select all” is allowed to mean.

Deciding what select-all means

The header checkbox never silently means more than the page. Titan’s own design library already answers this — a menu on the header checkbox with Select all n items, Select all on page, and Deselect all — see TITAN-DIV-19. None of it exists in code yet; this pattern is that menu’s specification, not a competing proposal. Where the question feels genuinely open, it is only the implementation that’s undecided — the scope distinction itself is design intent already recorded.

When this applies

  • A reader needs to act on more than one row at a time, on the same data type, with the same action.
  • The table or list is long enough that per-row controls would need to be pressed repeatedly to get the same result.
  • The action — export, tag, archive, delete — makes sense applied to a batch, not only to one record.

When it doesn’t

Structure

Behavior

Constraints

Content

Accessibility

  • The selection count is a live region, announced politely on change. A keyboard user checking rows gets no other confirmation that anything happened — see Table’s own accessibility section.
  • The bar appearing does not steal focus. Focus stays on the checkbox the reader just pressed.
  • Each row checkbox’s accessible name identifies the row: “Select row: Q3 Paid Search,” not “Checkbox” — see TITAN-CHK-02.
  • The header checkbox’s accessible name states its scope explicitly — “Select all on this page” — rather than the generic “Select all,” since what it selects is exactly the fact this pattern has to disambiguate.
  • Bulk action buttons are reachable in the same tab order as the rest of the toolbar; the bar does not trap focus.

Variations

Anti-patterns

Per-row action buttons repeated down every row. Cheap to build, expensive for anyone who has to click the same button fifty times to do one job. This is the exact case this pattern exists to replace. A “select all” that quietly means everything, including rows never shown. A reader who checked a header box expecting “this page” and got “every campaign in the account” has just run a bulk action on data they never saw. Scope has to be explicit, especially for anything destructive. Selection that survives a filter change unannounced. A reader who filtered to “Active,” selected four rows, then cleared the filter still has four rows selected — rows that may no longer even be visible. Acting on that selection now applies to a set the reader can’t see and didn’t choose in this view. Treating a partial bulk failure as a full success or a full failure. Clearing the whole selection because most of it worked hides the two rows that didn’t; failing the whole batch because two rows errored discards eighteen that succeeded. Either one makes the reader redo work that already happened correctly.
Last modified on September 2, 2026