KQ-2127 · COUNT/TAKEOVER

Count Takeover

A list header that changes role when rows are picked: the title leaves upward on the exit ease while the count rises in from below on springs.snap and the selection's actions rise after it in a cascade() stagger on snap, and clearing runs the same path backwards, the actions sinking in reverse order before the title comes back down. Each digit of the count is its own wheel that rolls on snap in the direction the count moved, and every action can answer a mixed selection with a reason — it stays focusable but aria-disabled, and hovering or focusing it slides the sentence in under the header. The list is a multi-select listbox (Space toggles, Shift with arrows or a click extends), Cmd or Ctrl+A selects all, Escape clears, and on narrow widths the secondary actions fold into a More menu.

KQ-2127 · COUNT/TAKEOVER

Shipments

48 in transit · updated 4 min ago

BSN-20418Tacoma, WA · Coldbrook RoastersFieldline FreightIn transitOct 19
BSN-20421Reno, NV · Gaugeworks SupplyWaylight CargoIn transitOct 20
BSN-20402Boise, ID · Fernworks StudioFieldline FreightDeliveredOct 16
BSN-20426Fresno, CA · Coldbrook RoastersWaylight CargoAwaiting pickupOct 21
BSN-20427Eugene, OR · Basin OutfittersFieldline FreightDraftOct 22
BSN-20411Spokane, WA · Gaugeworks SupplyWaylight CargoHeld at depotOct 18
BSN-20398Sacramento, CA · Fernworks StudioFieldline FreightDeliveredOct 15
BSN-20429Bend, OR · Basin OutfittersWaylight CargoAwaiting pickupOct 22
BSN-20423Provo, UT · Coldbrook RoastersFieldline FreightIn transitOct 20
BSN-20430Yakima, WA · Gaugeworks SupplyWaylight CargoDraftOct 23

Space picks a row · ⌘ or Ctrl+A selects all · Esc clears

no selection · last: none yet

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/count-takeover

Props

items
CountTakeoverItem[]
default defaultCountTakeoverItems
The rows: { id, ref, destination, customer, carrier, state: "draft" | "ready" | "transit" | "delivered" | "held", due }.
selection / defaultSelection
string[]
default []
Selected row ids, controlled or initial. Ids whose rows have gone are neither shown nor counted.
onSelectionChange
(ids: string[]) => void
default —
Fires from the click, key, Clear or action that changed the selection.
actions
CountTakeoverAction[]
default defaultCountTakeoverActions
What the header offers a selection: { id, label, icon, tone?: "default" | "danger", priority?: "primary" | "secondary", reason?: (selected) => string | null }. A reason turns the action off for that selection and is shown on hover or focus.
idleActions
CountTakeoverAction[]
default defaultCountTakeoverIdleActions
What the header offers with nothing selected; the last one is the primary button.
onAction
(actionId: string, ids: string[]) => void
default —
Fires when an action is taken, with the ids it applies to (empty for idle actions). An action that is off never fires it.
onSelectAll
(ids: string[]) => void
default —
Fires when everything is selected by the header checkbox or Cmd/Ctrl+A.
onClear
() => void
default —
Fires when the selection is cleared by Escape, Clear or the header checkbox.
clearOnAction
boolean
default true
Drop the selection once an action has been taken, so the header reverses to its title.
title
string
default "Shipments"
The list's title, and the accessible name of the piece and its listbox.
meta
string
default "48 in transit · updated 4 min ago"
The line under the title.
noun
{ one: string; many: string }
default { one: "shipment", many: "shipments" }
What one row is called, for the count and the announcements.
listHeight
number
default 168
Height of the scrolling list, px.
swapStyle
"rise" | "push" | "fold"
default "rise"
How the header changes role: the title rises out as the count rises in, a sideways push, or a fold about the header's horizontal axis.
density
"compact" | "regular" | "roomy"
default "regular"
Header and row height: 44/32, 48/40 or 52/48 px.
accent
"cobalt" | "plum" | "mint" | "ink" | string
default "cobalt"
Checkboxes, the selection wash, the count and the primary action: a named accent or any CSS colour.
status
"ready" | "loading" | "error"
default "ready"
List state: loading shows skeleton rows, error offers Retry.
onRetry
() => void
default —
Called by the error state's Retry button.
emptyText
string
default "No shipments match this view."
Shown when there are no rows.
disabled
boolean
default false
Turns the list and the header off.
className
string
default —
Classes for the outer section.