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.
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 — none of it exists in code yet (see
Known issues); 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.
Replaces or sits above the table’s toolbar once anything is selected. States the count and scope, holds the bulk actions. Built from Button and, for scope, a text line — the menu this deserves is design intent with nothing shipped yet, see Known issues.
Selection bar appears, stating the count and scope. Nothing else on the page moves.
Header checkbox checked
Selects every row on the current page — no more. If more rows match the active filter, the bar offers “Select all N matching” as a distinct, separately-triggered action.
Selection partial
Header checkbox reflects the page’s state only. There is no indeterminate checkbox state to show “some selected” with — see Known issues. The bar’s count is the only signal that a subset, not everything, is selected.
Filter, sort, or search changes
Selection clears. The set the reader selected was scoped to the rows they could see; carrying it across a changed result set silently redefines what “selected” refers to.
Navigating away and back
Selection does not persist.
Bulk action triggered
The action button enters loading, holding its width. The bar stays visible.
Bulk action succeeds, in full
Bar closes, selection clears, Toast confirms the count and action.
Bulk action partially fails
Selection does not clear on the rows that failed. Rows that succeeded drop out of the selection; failed rows stay selected so the reader can retry just those. An Alert states the split: “18 of 20 campaigns updated. 2 failed.”
Selecting the first row is what puts the page into selection mode. There is no separate “enter selection mode” control.
A mode the reader has to switch into deliberately is one extra step for the common case, which is checking a box because you want to act on that row.
TITAN-BULK-02
A bulk action states its count and scope before it runs.
Follows the same rule Table’s own row-count actions already state, rather than restating it.
TITAN-BULK-03
The header checkbox selects the current page only. Selecting every row matching a filter is a separate, explicitly-labeled action.
”Select all” over a filtered table is ambiguous between the page, the filter, and everything.
TITAN-BULK-04
The select-all checkbox shows checked only when every row on the page is selected. A partial selection is signaled by the bar’s count, never by the checkbox.
No indeterminate state exists to show “some” — see Known issues. Showing “checked” for a partial selection would misrepresent it.
TITAN-BULK-05
Selected-row feedback does not rely on fill color alone.
background-hover and background-selected resolve to the same value today (see Known issues), so color cannot be the only carrier of selection state. The checkbox’s own checked state and the bar’s count are what actually carry it.
TITAN-BULK-06
Selection clears when the filter, sort, or search that produced the current result set changes.
The selection was scoped to a specific set of visible rows. Carrying it forward silently applies it to a different set the reader never looked at.
TITAN-BULK-07
A destructive bulk action is confirmed once, for the batch, via Destructive confirmation’s bulk-destructive variation — never once per row.
Per-item confirmation on a routine batch action is exactly the friction that trains users to click through dialogs.
TITAN-BULK-08
On partial failure, rows that failed stay selected; rows that succeeded do not. The result states both counts.
The reader’s next likely action is retrying only the failures. Clearing the whole selection makes them reselect by hand; leaving succeeded rows selected invites re-running an action that already worked.
TITAN-BULK-09
Every selection checkbox — row and header — carries an accessible name identifying its scope.
A column of controls all announcing “checkbox” is unusable, and a group needs a name distinct from any one option’s — the same rule Checkbox’s own page already states.
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.”
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.
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.
The design library specifies a header-checkbox menu with “Select all n items,” “Select all on page,” and “Deselect all” — none of it exists in code. This pattern is that menu’s specification, per TITAN-BULK-03, not a competing proposal.
No indeterminate/mixed checkbox state exists in the design library, so TITAN-BULK-04 settles for the bar’s count as the only signal of a partial selection.
background-hover and background-selected resolve to the same value — a hovered row and a selected row currently look identical, which is why TITAN-BULK-05 doesn’t rely on fill color to carry selection state.
What “select all N matching” should do if N is large enough that running the action
synchronously would time out — Variations gestures at a background job without
naming a threshold.
Whether a retry after a partial failure should re-fetch the rows first, in case they changed
between the first attempt and the retry.
Whether selection should ever persist across a page reload within the same session, rather
than clearing unconditionally.
The header checkbox is scoped to the page, never to everything, because “select all” over a
filtered table has no single obvious meaning. The larger scope is a separate,
explicitly-labeled action rather than an implicit consequence of the same click — a reader who
wanted the page gets the page, and a reader who wanted everything has to say so.Selection clears on any change to the underlying result set because a selection is a claim
about specific rows, not a count. A changed filter is a changed context entirely — carrying
four selected rows across a filter change silently redefines what “those four” refers to, and
the reader never agreed to that redefinition.
Table and
List, the two containers this pattern
selects from. Checkbox, the row and header
controls. Destructive confirmation,
for the bulk-destructive variation a destructive batch action routes through.
Filtering & search, for the narrowing
that precedes selection and clears it on change.
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 real, current
limits on what this pattern can promise — not workarounds this page invents around them — are
recorded in Known issues rather than restated here.
Last modified on September 17, 2026
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Invoca","colors":{"primary":"#00A87F","light":"#00A87F","dark":"#0EEEB7"},"logo":{"light":"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/logo/light.svg?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=3ed629c5be28d08bd1a6580e72b6dbfa","dark":"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/logo/dark.svg?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=b64ce8e5cfa4f8c7893b2738e8131f45","href":"https://www.invoca.com/"},"favicon":"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/favicon.png?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=c846713bb1afdf274154a01d7e9abb8d","appearance":{"default":"light"},"background":{"decoration":"gradient"},"navbar":{"primary":{"type":"button","label":"Invoca Academy","href":"https://academy.invoca.com/"}},"footer":{"socials":{"linkedin":"https://www.linkedin.com/company/invoca-com","youtube":"https://www.youtube.com/channel/UCLQwNQFnN1OV1ACnlXICPKw"}},"fonts":{"body":{"family":"Gt America","source":"https://cdn.prod.website-files.com/5d82e225060d003d65ddae98/677d87009656fca63c0c7d8f_GT-America-Standard-Regular.woff2","format":"woff2"}},"contextual":{"options":["copy","download-pdf","view","assistant","chatgpt","claude","perplexity"],"display":"header"},"metadata":{"timestamp":true},"styling":{"latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"invoca-5bd45748","hasAudioNarration":false,"actualSubdomain":"invoca-5bd45748","customDomains":["docs.invoca.com"],"gitSource":{"type":"github","owner":"invoca","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae8bdbaca78e468455a6b97","collectionId":"54b26950-9181-41ce-985a-32d474ce8dd0","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae8bdbaca78e468455a6b97"},"feedback":{"thumbs":true,"agentFeedback":true,"contextualFeedback":{"allowEmail":false}},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"REMOVE_BRANDING":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED","enabled":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae8bdbaca78e468455a6b97","clientVersion":"0.0.4045","searchFilterCounts":[{"language":"default","tag":"Invoca Docs","count":666},{"language":"default","tag":"Guide","count":665},{"language":"default","tag":"Developer","count":191},{"language":"default","tag":"Integrations","count":184},{"language":"default","tag":"Invoca Design System","count":163},{"language":"default","tag":"API Documentation","count":151},{"language":"default","tag":"Campaign \u0026 Call Handling","count":127},{"language":"default","tag":"Insights \u0026 Analytics","count":101},{"language":"default","tag":"Network Integration","count":99},{"language":"default","tag":"Components","count":75}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":true,"enableContextualStarterQuestions":true,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"type":"link","url":"https://support.invoca.com/s/contactsupport"}},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":".custom-card .card img{width:60%;padding:1rem;margin:0 auto}a[href=\"https://academy.invoca.com/\"] span.absolute{background-color:#004030}#assistant-entry,#assistant-entry-mobile{background-color:#00a87f;border-color:#00a87f}#assistant-entry-mobile:hover,#assistant-entry:hover{background-color:#009973}#assistant-entry span,#assistant-entry svg,#assistant-entry-mobile span,#assistant-entry-mobile svg{color:#fff}.ivk-home{--ivk-forest:#0A231E;--ivk-footer-bg:#004030;--ivk-accent:#00A87F;--ivk-ink:#1F2121;--ivk-muted:#626464;--ivk-line:#E7E9E4;--ivk-bg:#FFFFFF;--ivk-sand:#F8FAF1;--ivk-banner:#D1FFD1;--ivk-card:#FFFFFF;--ivk-radius-btn:6px;--ivk-radius-card:16px;color:var(--ivk-ink);width:100%;max-width:1600px;margin:0 auto;padding:2rem clamp(1.25rem,4vw,4rem) 4rem}.dark .ivk-home,:root[data-theme=dark] .ivk-home{--ivk-bg:#10201B;--ivk-card:#16261F;--ivk-ink:#EAF1EC;--ivk-muted:#9BAAA1;--ivk-line:#223229;--ivk-sand:#16261F;--ivk-banner:#1C3A2C}.ivk-home a{color:inherit;text-decoration:none}.ivk-home footer a[href*=mintlify]{color:#9ea3a2}.dark .ivk-home footer a[href*=mintlify]{color:#6f7573}.ivk-home footer a[href*=mintlify]:hover{color:#4f5553}.dark .ivk-home footer a[href*=mintlify]:hover{color:#ced3d1}.ivk-home img,.ivk-home svg{display:block}.ivk-home-announce,.ivk-home-hero{border-radius:var(--ivk-radius-card)}.ivk-home-announce{background:var(--ivk-banner);color:var(--ivk-ink);font-size:13.5px;font-weight:500;text-align:center;padding:9px 16px;margin-bottom:20px}.ivk-home-announce a{color:var(--ivk-footer-bg);font-weight:600;text-decoration:underline;margin-left:6px}.ivk-home-hero{position:relative;overflow:hidden;background:var(--ivk-forest);color:#fff;padding:56px 32px}.ivk-home-hero-eyebrow{display:inline-flex;align-items:center;gap:8px;color:#fff;font-size:13px;font-weight:500;border:1px solid rgba(255,255,255,.28);border-radius:999px;padding:6px 14px;margin:0 0 22px}.ivk-home-hero h1{font-size:clamp(28px,4.2vw,44px);font-weight:700;line-height:1.1;letter-spacing:-.01em;max-width:17ch;margin:0 0 16px;color:#fff}.ivk-home-hero h1 .ivk-home-hl{color:#00b388}.ivk-home-hero-lede{font-size:16.5px;color:rgba(255,255,255,.78);max-width:48ch;margin:0 0 30px;line-height:1.55}.ivk-home-search-field{display:flex;align-items:center;gap:10px;background:#fff;border-radius:var(--ivk-radius-btn);padding:13px 16px;max-width:560px;box-shadow:0 14px 34px rgba(0,0,0,.28);cursor:pointer;border:0;width:100%;text-align:left;font-family:inherit}.ivk-home-search-field input{border:0;outline:0;flex:1;font-size:15px;font-family:inherit;color:#1f2121;background:0 0;pointer-events:none}.ivk-home-search-field input::placeholder{color:#626464}.ivk-home-search-field .ivk-home-icon{color:#626464;flex:none}.ivk-home-search-field kbd{font-size:11.5px;color:#626464;border:1px solid #e7e9e4;border-radius:5px;padding:2px 6px}.ivk-home-popular{margin-top:26px;display:flex;flex-wrap:wrap;gap:8px;align-items:center}.ivk-home-popular .ivk-home-label{color:rgba(255,255,255,.62);font-size:13px;margin-right:4px}.ivk-home-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.2);color:#fff;font-size:13px;padding:7px 12px;border-radius:999px}.ivk-home-chip:hover{background:rgba(255,255,255,.16)}.ivk-home-note-banner{background:var(--ivk-sand);border:1px solid var(--ivk-line);border-radius:var(--ivk-radius-card);padding:16px 20px;font-size:13.5px;color:var(--ivk-muted);line-height:1.55;margin-top:24px}.ivk-home-note-banner strong{color:var(--ivk-ink)}.ivk-home-band{padding:60px 0}.ivk-home-band-alt{background:var(--ivk-sand);border-radius:var(--ivk-radius-card)}.ivk-home-section-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:26px;flex-wrap:wrap}.ivk-home-section-head h2,.ivk-home-topic-tile h3{font-size:23px;font-weight:700;letter-spacing:-.01em;margin:0;color:var(--ivk-ink)}.ivk-home-section-head .ivk-home-meta,.ivk-home-section-sub{color:var(--ivk-muted);font-size:13.5px}.ivk-home-section-sub{font-size:14.5px;max-width:62ch;margin:-14px 0 26px;line-height:1.55}.ivk-home-topic-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;align-items:start}@media (min-width:1400px){.ivk-home-topic-grid{grid-template-columns:repeat(4,1fr)}}@media (max-width:860px){.ivk-home-topic-grid{grid-template-columns:repeat(2,1fr)}}@media (max-width:600px){.ivk-home-topic-grid{grid-template-columns:1fr}}.ivk-home-topic-tile{background:var(--ivk-card);border:1px solid var(--ivk-line);border-radius:var(--ivk-radius-card);transition:border-color .15s ease}.ivk-home-topic-tile:hover{border-color:color-mix(in srgb,var(--ivk-accent) 40%,var(--ivk-line))}.ivk-home-t-head{display:block;width:100%;padding:22px 22px 18px;cursor:pointer;background:0 0;border:0;text-align:left;font-family:inherit;color:inherit}.ivk-home-row-top{display:flex;align-items:center;justify-content:space-between;gap:10px}.ivk-home-icon-wrap{width:36px;height:36px;border-radius:10px;background:rgba(0,168,127,.12);color:var(--ivk-accent);display:flex;align-items:center;justify-content:center}.ivk-home-count{font-size:12px;color:var(--ivk-muted);white-space:nowrap}.ivk-home-title-row{display:flex;align-items:flex-start;gap:6px;margin:12px 0 4px}.ivk-home-topic-tile h3{font-size:16.5px;font-weight:600;letter-spacing:-.005em;line-height:1.3;min-height:2.6em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.ivk-home-tag-pill{flex:none;margin-top:2px;padding:2px 4px;border-radius:6px;font-size:.65rem;font-weight:700;line-height:13px;color:var(--ivk-accent);background:rgba(0,168,127,.1)}.dark .ivk-home-tag-pill,:root[data-theme=dark] .ivk-home-tag-pill{color:#1dc79a;background:rgba(29,199,154,.15)}.ivk-home-desc{font-size:13.5px;color:var(--ivk-muted);margin:0;line-height:1.5;min-height:3em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.ivk-home-expand-cue{display:flex;align-items:center;gap:6px;margin-top:14px;font-size:12.5px;color:var(--ivk-accent);font-weight:600}.ivk-home-expand-cue svg{transition:transform .18s ease}.ivk-home-topic-tile.ivk-home-open .ivk-home-expand-cue svg{transform:rotate(180deg)}.ivk-home-t-panel{border-top:1px solid var(--ivk-line);margin-top:2px;padding:16px 22px 22px}.ivk-home-t-panel ul{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:9px}.ivk-home-t-panel li a{font-size:13px;color:var(--ivk-ink);display:flex;align-items:center;gap:7px}.ivk-home-dev-card h3 a:hover,.ivk-home-t-panel li a:hover,.ivk-home-viewall{color:var(--ivk-accent)}.ivk-home-t-panel li a svg{flex:none;opacity:.5}.ivk-home-viewall{font-size:12.5px;font-weight:600}.ivk-home-dev-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}@media (max-width:700px){.ivk-home-dev-grid{grid-template-columns:1fr}}.ivk-home-dev-card{background:var(--ivk-card);border:1px solid var(--ivk-line);border-radius:var(--ivk-radius-card);padding:18px;display:flex;gap:12px;align-items:flex-start}.ivk-home-dev-card .ivk-home-icon-wrap{background:var(--ivk-forest);color:#fff;width:32px;height:32px;border-radius:9px}.ivk-home-dev-card h3{font-size:14.5px;font-weight:600;margin:0 0 3px;color:var(--ivk-ink)}.ivk-home-dev-card p{font-size:13px;color:var(--ivk-muted);margin:0;line-height:1.45}"}],"page":{"pagePath":"invoca-design-system/patterns/bulk-selection","slug":"/invoca-design-system/patterns/bulk-selection","pageMetadata":{"title":"Bulk selection","description":"Selecting many rows at once and acting on them as a single batch.","icon":"list-checks","keywords":["bulk actions","multi-select","select all","checkbox","batch","mass action"],"href":"/invoca-design-system/patterns/bulk-selection"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Selecting many rows at once and acting on them as a single batch.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,em:`em`,li:`li`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Mermaid,Table,Tip}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Mermaid)_missingMdxReference(`Mermaid`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsx(Heading,{level:`2`,id:`the-problem`,children:`The problem`}),`\n`,_jsx(_components.p,{children:`A reader looking at a table of a hundred campaigns doesn’t want to delete, export, or tag them\none at a time. They want to check the ones they mean and act on all of them at once. Without a\ndeliberate pattern for this, every team either repeats a row of action buttons on every row —\nexpensive to scan and expensive to click fifty times — or bolts a bespoke selection model onto\nwhichever table needed it first.`}),`\n`,_jsx(_components.p,{children:`Selection is also where ambiguity becomes expensive. “Select all” over a table sitting behind an\nactive filter has at least three plausible meanings: every row on the current page, every row\nmatching the filter, or every row that exists. Get the scope wrong on an export and the reader\ngets a stale file. Get it wrong on a delete and the reader loses data that was never on screen.`}),`\n`,_jsxs(_components.p,{children:[`This pattern is not the checkbox. `,_jsx(_components.strong,{children:`The pattern is the bar that appears once something is\nselected, and the rule for what “select all” is allowed to mean.`})]}),`\n`,_jsx(Heading,{level:`2`,id:`deciding-what-select-all-means`,children:`Deciding what select-all means`}),`\n`,_jsx(Mermaid,{chart:`flowchart TD\n A[Reader checks a row's checkbox] --> B[Selection bar appears,\u003cbr/>stating the count]\n B --> C[Reader checks the header checkbox]\n C --> D[Selects every row on the current page only]\n D --> E{Does the filter or result set\u003cbr/>contain more rows than fit on this page?}\n E -->|Yes| F[\"Bar offers a separate action:\u003cbr/>'Select all N matching these filters'\"]\n E -->|No| G[The page is the whole result set —\u003cbr/>the header checkbox already covers it]`}),`\n`,_jsx(Tip,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The header checkbox never silently means more than the page.`}),` Titan’s own design library\nalready answers this — a menu on the header checkbox with `,_jsxs(_components.strong,{children:[`Select all `,_jsx(_components.em,{children:`n`}),` items`]}),`, `,_jsx(_components.strong,{children:`Select\nall on page`}),`, and `,_jsx(_components.strong,{children:`Deselect all`}),` — none of it exists in code yet (see\n`,_jsx(_components.a,{href:`#known-issues`,children:`Known issues`}),`); this pattern is that menu’s specification, not a competing\nproposal. Where the question feels genuinely open, it is only the implementation that’s\nundecided — the scope distinction itself is design intent already recorded.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`vocabulary`,children:`Vocabulary`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Term`}),_jsx(_components.th,{children:`Also called`}),_jsx(_components.th,{children:`The system uses`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Select all`}),_jsx(_components.td,{children:`Select everything, check all`}),_jsxs(_components.td,{children:[`Ambiguous on its own — this page always qualifies it: `,_jsx(_components.strong,{children:`select all on page`}),`, or `,_jsx(_components.strong,{children:`select all N matching`})]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Selection bar`}),_jsx(_components.td,{children:`Bulk action bar, toolbar`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Selection bar`}),` — appears once anything is selected; states the count and scope, holds the bulk actions`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Scope`}),_jsx(_components.td,{children:`Selection scope`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Scope`}),` — which rows a selection actually covers: the current page, or every row matching the active filter`]})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`when-this-applies`,children:`When this applies`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`A reader needs to act on more than one row at a time, on the same data type, with the same\naction.`}),`\n`,_jsx(_components.li,{children:`The table or list is long enough that per-row controls would need to be pressed repeatedly to\nget the same result.`}),`\n`,_jsx(_components.li,{children:`The action — export, tag, archive, delete — makes sense applied to a batch, not only to one\nrecord.`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`when-it-doesn’t`,children:`When it doesn’t`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Situation`}),_jsx(_components.th,{children:`Do this instead`}),_jsx(_components.th,{children:`Why`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Acting on exactly one row, most of the time`}),_jsxs(_components.td,{children:[`A `,_jsx(_components.a,{href:`/invoca-design-system/components/data-display/table#composition`,children:`row action`}),` in a trailing column`]}),_jsx(_components.td,{children:`Selection mode is overhead for a task that is usually singular.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The action needs its own confirmation per item, with different consequences each time`}),_jsx(_components.td,{children:`Handle each confirmation individually, not as a batch`}),_jsx(_components.td,{children:`Bulk selection assumes one action applies uniformly; per-item review defeats the batching.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The list is short enough to see and click every item without scrolling`}),_jsx(_components.td,{children:`Nothing — repeat the row action`}),_jsx(_components.td,{children:`The pattern earns its cost on a list a reader can’t act on one row at a time without real friction.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The reader needs to narrow the list before acting, not act on all of it`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/filtering-and-search`,children:`Filtering \u0026 search`})}),_jsx(_components.td,{children:`Selection is what happens after narrowing, not instead of it.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`structure`,children:`Structure`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Order`}),_jsx(_components.th,{children:`Component`}),_jsx(_components.th,{children:`Role`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`1`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/forms/checkbox`,children:`Checkbox`}),` — row`]}),_jsx(_components.td,{children:`Enters that row into the selection. Independent per row.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`2`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/forms/checkbox`,children:`Checkbox`}),` — header / select-all`]}),_jsx(_components.td,{children:`Selects every row on the current page. Never implicitly more.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`3`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/data-display/table`,children:`Table`}),` or `,_jsx(_components.a,{href:`/invoca-design-system/components/data-display/list`,children:`List`})]}),_jsx(_components.td,{children:`The container being selected from.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`4`}),_jsxs(_components.td,{children:[`Selection bar `,_jsx(_components.em,{children:`(composed — no export)`})]}),_jsxs(_components.td,{children:[`Replaces or sits above the table’s toolbar once anything is selected. States the count and scope, holds the bulk actions. Built from `,_jsx(_components.a,{href:`/invoca-design-system/components/actions/button`,children:`Button`}),` and, for scope, a text line — the menu this deserves is design intent with nothing shipped yet, see `,_jsx(_components.a,{href:`#known-issues`,children:`Known issues`}),`.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`5`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/actions/button`,children:`Button`}),` — bulk action`]}),_jsx(_components.td,{children:`Triggers the batch action. Label states the count: “Delete 4 Campaigns.”`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`6`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`})}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Destructive bulk actions only`}),` — the batch’s bulk-destructive variation.`]})]})]})]}),`\n`,_jsx(CodeBlock,{numberOfLines:`11`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`11`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`┌─────────────────────────────────────────────┐`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☑ 4 campaigns selected [Export] [Delete] │ ← selection bar`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`├─────────────────────────────────────────────┤`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☑ Campaign Status Calls │ ← header checkbox: page only`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☑ Q3 Paid Search Active 1,284 │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☑ Q3 Display Active 402 │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☑ Holiday Promo Paused 118 │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☑ Retargeting Active 310 │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`│ ☐ Brand Search Active 892 │`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`└─────────────────────────────────────────────┘`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsx(Heading,{level:`2`,id:`behavior`,children:`Behavior`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`State`}),_jsx(_components.th,{children:`Behavior`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`First row checked`}),_jsx(_components.td,{children:`Selection bar appears, stating the count and scope. Nothing else on the page moves.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Header checkbox checked`}),_jsxs(_components.td,{children:[`Selects every row on the current page — no more. If more rows match the active filter, the bar offers “Select all `,_jsx(_components.em,{children:`N`}),` matching” as a distinct, separately-triggered action.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Selection partial`}),_jsxs(_components.td,{children:[`Header checkbox reflects the page’s state only. There is no indeterminate checkbox state to show “some selected” with — see `,_jsx(_components.a,{href:`#known-issues`,children:`Known issues`}),`. The bar’s count is the only signal that a subset, not everything, is selected.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Filter, sort, or search changes`}),_jsx(_components.td,{children:`Selection clears. The set the reader selected was scoped to the rows they could see; carrying it across a changed result set silently redefines what “selected” refers to.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Navigating away and back`}),_jsx(_components.td,{children:`Selection does not persist.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk action triggered`}),_jsxs(_components.td,{children:[`The action button enters `,_jsx(_components.code,{children:`loading`}),`, holding its width. The bar stays visible.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk action succeeds, in full`}),_jsxs(_components.td,{children:[`Bar closes, selection clears, `,_jsx(_components.a,{href:`/invoca-design-system/components/feedback/toast`,children:`Toast`}),` confirms the count and action.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk action partially fails`}),_jsxs(_components.td,{children:[`Selection does not clear on the rows that failed. Rows that succeeded drop out of the selection; failed rows stay selected so the reader can retry just those. An `,_jsx(_components.a,{href:`/invoca-design-system/components/feedback/alert`,children:`Alert`}),` states the split: “18 of 20 campaigns updated. 2 failed.”`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk action is destructive`}),_jsxs(_components.td,{children:[`Routes through `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`}),`’s bulk-destructive variation before running at all.`]})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`constraints`,children:`Constraints`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`ID`}),_jsx(_components.th,{children:`Constraint`}),_jsx(_components.th,{children:`Rationale`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-01`})}),_jsx(_components.td,{children:`Selecting the first row is what puts the page into selection mode. There is no separate “enter selection mode” control.`}),_jsx(_components.td,{children:`A mode the reader has to switch into deliberately is one extra step for the common case, which is checking a box because you want to act on that row.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-02`})}),_jsx(_components.td,{children:`A bulk action states its count and scope before it runs.`}),_jsx(_components.td,{children:`Follows the same rule Table’s own row-count actions already state, rather than restating it.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-03`})}),_jsx(_components.td,{children:`The header checkbox selects the current page only. Selecting every row matching a filter is a separate, explicitly-labeled action.`}),_jsx(_components.td,{children:`”Select all” over a filtered table is ambiguous between the page, the filter, and everything.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-04`})}),_jsx(_components.td,{children:`The select-all checkbox shows checked only when every row on the page is selected. A partial selection is signaled by the bar’s count, never by the checkbox.`}),_jsxs(_components.td,{children:[`No indeterminate state exists to show “some” — see `,_jsx(_components.a,{href:`#known-issues`,children:`Known issues`}),`. Showing “checked” for a partial selection would misrepresent it.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-05`})}),_jsx(_components.td,{children:`Selected-row feedback does not rely on fill color alone.`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`background-hover`}),` and `,_jsx(_components.code,{children:`background-selected`}),` resolve to the same value today (see `,_jsx(_components.a,{href:`#known-issues`,children:`Known issues`}),`), so color cannot be the only carrier of selection state. The checkbox’s own checked state and the bar’s count are what actually carry it.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-06`})}),_jsx(_components.td,{children:`Selection clears when the filter, sort, or search that produced the current result set changes.`}),_jsx(_components.td,{children:`The selection was scoped to a specific set of visible rows. Carrying it forward silently applies it to a different set the reader never looked at.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-07`})}),_jsxs(_components.td,{children:[`A destructive bulk action is confirmed once, for the batch, via `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`}),`’s bulk-destructive variation — never once per row.`]}),_jsx(_components.td,{children:`Per-item confirmation on a routine batch action is exactly the friction that trains users to click through dialogs.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-08`})}),_jsx(_components.td,{children:`On partial failure, rows that failed stay selected; rows that succeeded do not. The result states both counts.`}),_jsx(_components.td,{children:`The reader’s next likely action is retrying only the failures. Clearing the whole selection makes them reselect by hand; leaving succeeded rows selected invites re-running an action that already worked.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-BULK-09`})}),_jsx(_components.td,{children:`Every selection checkbox — row and header — carries an accessible name identifying its scope.`}),_jsx(_components.td,{children:`A column of controls all announcing “checkbox” is unusable, and a group needs a name distinct from any one option’s — the same rule Checkbox’s own page already states.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`content`,children:`Content`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Element`}),_jsx(_components.th,{children:`✅`}),_jsx(_components.th,{children:`❌`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bar count`}),_jsx(_components.td,{children:`4 campaigns selected`}),_jsx(_components.td,{children:`4 items selected`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Select-all beyond the page`}),_jsx(_components.td,{children:`Select all 128 campaigns matching these filters`}),_jsx(_components.td,{children:`Select all`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk action button`}),_jsx(_components.td,{children:`Delete 4 Campaigns`}),_jsx(_components.td,{children:`Delete`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Partial failure`}),_jsx(_components.td,{children:`18 of 20 campaigns updated. 2 failed.`}),_jsx(_components.td,{children:`Some updates failed.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`accessibility`,children:`Accessibility`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`The selection count is a live region, announced politely on change. A keyboard user checking\nrows gets no other confirmation that anything happened — see\n`,_jsx(_components.a,{href:`/invoca-design-system/components/data-display/table#accessibility`,children:`Table’s own accessibility section`}),`.`]}),`\n`,_jsx(_components.li,{children:`The bar appearing does not steal focus. Focus stays on the checkbox the reader just pressed.`}),`\n`,_jsx(_components.li,{children:`Each row checkbox’s accessible name identifies the row: “Select row: Q3 Paid Search,” not\n“Checkbox.”`}),`\n`,_jsx(_components.li,{children:`The header checkbox’s accessible name states its scope explicitly — “Select all on this\npage” — rather than the generic “Select all,” since what it selects is exactly the fact this\npattern has to disambiguate.`}),`\n`,_jsx(_components.li,{children:`Bulk action buttons are reachable in the same tab order as the rest of the toolbar; the bar\ndoes not trap focus.`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`variations`,children:`Variations`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variation`}),_jsx(_components.th,{children:`When`}),_jsx(_components.th,{children:`Change`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Selection in a List, not a Table`}),_jsx(_components.td,{children:`No columns, no header row`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/data-display/list`,children:`List`}),` has no header checkbox to compose a select-all menu onto — state scope in the bar’s copy alone, since there is no control to carry it.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk destructive action`}),_jsx(_components.td,{children:`The action deletes or otherwise destroys`}),_jsxs(_components.td,{children:[`Route through `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`}),`’s bulk-destructive variation. Title states the count; body names the highest-consequence item.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Selecting a very large matching set (thousands of rows)`}),_jsx(_components.td,{children:`“Select all matching” spans more than a page or two of results`}),_jsx(_components.td,{children:`State that the action may take time, and consider running it as a tracked background job rather than blocking the bar on a synchronous batch.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`anti-patterns`,children:`Anti-patterns`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Per-row action buttons repeated down every row.`}),` Cheap to build, expensive for anyone who\nhas to click the same button fifty times to do one job. This is the exact case this pattern\nexists to replace.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`A “select all” that quietly means everything, including rows never shown.`}),` A reader who\nchecked a header box expecting “this page” and got “every campaign in the account” has just\nrun a bulk action on data they never saw. Scope has to be explicit, especially for anything\ndestructive.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Selection that survives a filter change unannounced.`}),` A reader who filtered to “Active,”\nselected four rows, then cleared the filter still has four rows selected — rows that may no\nlonger even be visible. Acting on that selection now applies to a set the reader can’t see and\ndidn’t choose in this view.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Treating a partial bulk failure as a full success or a full failure.`}),` Clearing the whole\nselection because most of it worked hides the two rows that didn’t; failing the whole batch\nbecause two rows errored discards eighteen that succeeded. Either one makes the reader redo\nwork that already happened correctly.`]}),`\n`,_jsx(Heading,{level:`2`,id:`known-issues`,children:`Known issues`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`ID`}),_jsx(_components.th,{children:`Kind`}),_jsx(_components.th,{children:`What`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/foundations/divergences#titan-div-19`,children:`TITAN-DIV-19`})}),_jsx(_components.td,{children:`Divergence`}),_jsxs(_components.td,{children:[`The design library specifies a header-checkbox menu with “Select all `,_jsx(_components.em,{children:`n`}),` items,” “Select all on page,” and “Deselect all” — none of it exists in code. This pattern is that menu’s specification, per `,_jsx(_components.a,{href:`#constraints`,children:`TITAN-BULK-03`}),`, not a competing proposal.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/foundations/open-decisions#titan-gap-33`,children:`TITAN-GAP-33`})}),_jsx(_components.td,{children:`Open decision`}),_jsxs(_components.td,{children:[`No indeterminate/mixed checkbox state exists in the design library, so `,_jsx(_components.a,{href:`#constraints`,children:`TITAN-BULK-04`}),` settles for the bar’s count as the only signal of a partial selection.`]})]}),_jsxs(_components.tr,{children:[_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/foundations/divergences#titan-div-20`,children:`TITAN-DIV-20`}),` / `,_jsx(_components.a,{href:`/invoca-design-system/foundations/open-decisions#titan-gap-04`,children:`TITAN-GAP-04`})]}),_jsx(_components.td,{children:`Divergence / Open decision`}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`background-hover`}),` and `,_jsx(_components.code,{children:`background-selected`}),` resolve to the same value — a hovered row and a selected row currently look identical, which is why `,_jsx(_components.a,{href:`#constraints`,children:`TITAN-BULK-05`}),` doesn’t rely on fill color to carry selection state.`]})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`gaps-in-the-current-rules`,children:`Gaps in the current rules`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`What “select all N matching” should do if N is large enough that running the action\nsynchronously would time out — `,_jsx(_components.a,{href:`#variations`,children:`Variations`}),` gestures at a background job without\nnaming a threshold.`]}),`\n`,_jsx(_components.li,{children:`Whether a retry after a partial failure should re-fetch the rows first, in case they changed\nbetween the first attempt and the retry.`}),`\n`,_jsx(_components.li,{children:`Whether selection should ever persist across a page reload within the same session, rather\nthan clearing unconditionally.`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`why-it-works-this-way`,children:`Why it works this way`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The header checkbox is scoped to the page, never to everything, because “select all” over a\nfiltered table has no single obvious meaning.`}),` The larger scope is a separate,\nexplicitly-labeled action rather than an implicit consequence of the same click — a reader who\nwanted the page gets the page, and a reader who wanted everything has to say so.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Selection clears on any change to the underlying result set because a selection is a claim\nabout specific rows, not a count.`}),` A changed filter is a changed context entirely — carrying\nfour selected rows across a filter change silently redefines what “those four” refers to, and\nthe reader never agreed to that redefinition.`]}),`\n`,_jsx(Heading,{level:`2`,id:`related`,children:`Related`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/data-display/table`,children:`Table`}),` and\n`,_jsx(_components.a,{href:`/invoca-design-system/components/data-display/list`,children:`List`}),`, the two containers this pattern\nselects from. `,_jsx(_components.a,{href:`/invoca-design-system/components/forms/checkbox`,children:`Checkbox`}),`, the row and header\ncontrols. `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`}),`,\nfor the bulk-destructive variation a destructive batch action routes through.\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/filtering-and-search`,children:`Filtering \u0026 search`}),`, for the narrowing\nthat precedes selection and clears it on change.`]}),`\n`,_jsx(Heading,{level:`2`,id:`status`,children:`Status`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Exemplar page — first pass.`}),` This is a `,_jsx(_components.em,{children:`proposal`}),` for review, not established policy. No\nTitan design-library review or shipped Invoca screen backs this page — it is built from\ngeneral interaction-design practice and from constraints `,_jsx(_components.a,{href:`/invoca-design-system/components/data-display/table`,children:`Table`}),`,\n`,_jsx(_components.a,{href:`/invoca-design-system/components/data-display/list`,children:`List`}),`, and\n`,_jsx(_components.a,{href:`/invoca-design-system/components/forms/checkbox`,children:`Checkbox`}),` already establish. Two real, current\nlimits on what this pattern can promise — not workarounds this page invents around them — are\nrecorded in `,_jsx(_components.a,{href:`#known-issues`,children:`Known issues`}),` rather than restated here.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Bulk selection","description":"Selecting many rows at once and acting on them as a single batch.","icon":"list-checks","keywords":["bulk actions","multi-select","select all","checkbox","batch","mass action"],"href":"/invoca-design-system/patterns/bulk-selection"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"The problem","slug":"the-problem","depth":2,"children":[]},{"title":"Deciding what select-all means","slug":"deciding-what-select-all-means","depth":2,"children":[]},{"title":"Vocabulary","slug":"vocabulary","depth":2,"children":[]},{"title":"When this applies","slug":"when-this-applies","depth":2,"children":[]},{"title":"When it doesn’t","slug":"when-it-doesn’t","depth":2,"children":[]},{"title":"Structure","slug":"structure","depth":2,"children":[]},{"title":"Behavior","slug":"behavior","depth":2,"children":[]},{"title":"Constraints","slug":"constraints","depth":2,"children":[]},{"title":"Content","slug":"content","depth":2,"children":[]},{"title":"Accessibility","slug":"accessibility","depth":2,"children":[]},{"title":"Variations","slug":"variations","depth":2,"children":[]},{"title":"Anti-patterns","slug":"anti-patterns","depth":2,"children":[]},{"title":"Known issues","slug":"known-issues","depth":2,"children":[]},{"title":"Gaps in the current rules","slug":"gaps-in-the-current-rules","depth":2,"children":[]},{"title":"Why it works this way","slug":"why-it-works-this-way","depth":2,"children":[]},{"title":"Related","slug":"related","depth":2,"children":[]},{"title":"Status","slug":"status","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"invoca-5bd45748","siteName":"Invoca","title":"Bulk selection - Invoca","relatedPagesConfig":{"enabled":true,"limit":5,"mode":"automatic"},"contextualStarterQuestions":[{"_id":"6ab71c02fc74c9b83ba92cb9","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"What does bulk selection solve?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/bulk-selection","createdAt":"2026-09-26T01:12:34.732Z","updatedAt":"2026-09-26T01:12:34.732Z","__v":0},{"_id":"6ab71c02fc74c9b83ba92cba","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"How to avoid ambiguous selections?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/bulk-selection","createdAt":"2026-09-26T01:12:34.732Z","updatedAt":"2026-09-26T01:12:34.732Z","__v":0},{"_id":"6ab71c02fc74c9b83ba92cb8","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"How do I handle select all?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/bulk-selection","createdAt":"2026-09-26T01:12:34.732Z","updatedAt":"2026-09-26T01:12:34.732Z","__v":0}],"navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-17T18:53:35.936Z","gitLastModified":"2026-09-17T18:53:06.000Z","originalFileLocation":"invoca-design-system/patterns/bulk-selection.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Selecting many rows at once and acting on them as a single batch.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Invoca\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Bulk selection - Invoca\">\u003cmeta data-mint-head property=\"og:description\" content=\"Selecting many rows at once and acting on them as a single batch.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Invoca\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://invoca-5bd45748.mintlify.app/_mintlify/api/og/v2?division=Patterns\u0026amp;title=Bulk+selection\u0026amp;description=Selecting+many+rows+at+once+and+acting+on+them+as+a+single+batch.\u0026amp;theme=1c2016f9c5ca3323f39e5905\u0026amp;signature=b453f5cf80f24c0912949469d06c274f01aa4e87f0cbbd49fa04a3accf367f8d\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Bulk selection - Invoca\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Selecting many rows at once and acting on them as a single batch.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://invoca-5bd45748.mintlify.app/_mintlify/api/og/v2?division=Patterns\u0026amp;title=Bulk+selection\u0026amp;description=Selecting+many+rows+at+once+and+acting+on+them+as+a+single+batch.\u0026amp;theme=1c2016f9c5ca3323f39e5905\u0026amp;signature=b453f5cf80f24c0912949469d06c274f01aa4e87f0cbbd49fa04a3accf367f8d\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Invoca\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#00A87F\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/invoca-design-system/patterns/bulk-selection.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.invoca.com/#organization\",\"name\":\"Invoca\",\"url\":\"https://docs.invoca.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/logo/light.svg?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=3ed629c5be28d08bd1a6580e72b6dbfa\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.invoca.com#website\",\"name\":\"Invoca\",\"url\":\"https://docs.invoca.com\",\"publisher\":{\"@id\":\"https://docs.invoca.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection#webpage\",\"url\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection\",\"name\":\"Bulk selection\",\"description\":\"Selecting many rows at once and acting on them as a single batch.\",\"dateModified\":\"2026-09-17T18:53:06.000Z\",\"isPartOf\":{\"@id\":\"https://docs.invoca.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Patterns\",\"item\":\"https://docs.invoca.com/invoca-design-system/patterns/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Bulk selection\",\"item\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection#article\",\"headline\":\"Bulk selection\",\"name\":\"Bulk selection\",\"description\":\"Selecting many rows at once and acting on them as a single batch.\",\"url\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection\",\"mainEntityOfPage\":{\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/bulk-selection#webpage\"},\"dateModified\":\"2026-09-17T18:53:06.000Z\",\"keywords\":\"bulk actions, multi-select, select all, checkbox, batch, mass action\",\"publisher\":{\"@id\":\"https://docs.invoca.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.invoca.com#website\"}}]}\u003c/script>","siteName":"Invoca","nav":{"global":null,"products":[{"product":"Invoca Docs","pages":[{"title":"Invoca Docs","href":""}]},{"product":"Developer","pages":[{"title":"Developer","href":"/en/latest"}]},{"product":"Invoca Design System","icon":"palette","color":{"light":"#00b388","dark":"#00b388"},"description":"","tabs":[{"tab":"Get started","icon":"rocket","pages":[{"title":"Get started","href":"/invoca-design-system"}]},{"tab":"Foundations","icon":"palette","pages":[{"title":"Foundations","href":"/invoca-design-system/foundations/overview"}]},{"tab":"Content","icon":"font","pages":[{"title":"Content","href":"/invoca-design-system/content/voice-and-tone"}]},{"tab":"Components","icon":"shapes","pages":[{"title":"Components","href":"/invoca-design-system/components/overview"}]},{"tab":"Patterns","icon":"clipboard-list","groups":[{"group":"Patterns","root":{"title":"Patterns overview","icon":"layout-template","href":"/invoca-design-system/patterns/overview"},"directory":"card","pages":[{"title":"Destructive confirmation","icon":"trash-2","href":"/invoca-design-system/patterns/destructive-confirmation"},{"title":"Form validation","icon":"clipboard-check","href":"/invoca-design-system/patterns/form-validation"},{"title":"Empty \u0026 zero states","icon":"inbox","href":"/invoca-design-system/patterns/empty-and-zero-states"},{"title":"Loading \u0026 skeletons","icon":"loader","href":"/invoca-design-system/patterns/loading-and-skeletons"},{"title":"Error handling","icon":"octagon-alert","href":"/invoca-design-system/patterns/error-handling"},{"title":"Filtering and search","description":"Narrowing a list down to what someone wants, with deterministic filters and a search box — not natural-language interpretation.","icon":"filter","href":"/invoca-design-system/patterns/filtering-and-search"},{"title":"Bulk selection","icon":"list-checks","href":"/invoca-design-system/patterns/bulk-selection"},{"title":"Inline editing","description":"Editing a value in place, and when that stops being the right idea.","icon":"pencil","href":"/invoca-design-system/patterns/inline-editing"},{"title":"Progressive disclosure","icon":"chevrons-down-up","href":"/invoca-design-system/patterns/progressive-disclosure"},{"title":"Notifications","icon":"bell","href":"/invoca-design-system/patterns/notifications"},{"title":"Footers","icon":"panel-bottom","href":"/invoca-design-system/patterns/footers"},{"group":"CRUD","root":{"title":"CRUD overview","icon":"database","href":"/invoca-design-system/patterns/crud/overview"},"pages":[{"title":"Create","icon":"circle-plus","href":"/invoca-design-system/patterns/crud/create"},{"title":"Read","icon":"eye","href":"/invoca-design-system/patterns/crud/read"},{"title":"Update","icon":"pencil-line","href":"/invoca-design-system/patterns/crud/update"}]}]}]},{"tab":"Views","icon":"table-columns","pages":[{"title":"Views","href":"/invoca-design-system/views/overview"}]},{"tab":"AI Experience","icon":"robot","pages":[{"title":"AI Experience","href":"/invoca-design-system/ai-experience/overview"}]},{"tab":"Contribute","icon":"code-pull-request","pages":[{"title":"Contribute","href":"/invoca-design-system/contribute/governance"}]},{"tab":"Open Issues","icon":"triangle-exclamation","pages":[{"title":"Open Issues","href":"/invoca-design-system/foundations/divergences"}]}]}]},"basePath":"","title":"Bulk selection - Invoca","buildId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","deploymentId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","dynamics":[],"chunks":[]}