KQ-566 · DENSITY/GRID
Density Grid
A members table with a density switch. Changing density is a layout animation on glide: rows are keyed by id, so each one keeps its identity and tightens in place — height, gutters and avatar closing at once — rather than the table reprinting itself at a new size. The switch is a radio group where Left and Right step between the three stops without wrapping, Home and End jump to comfortable and compact, and Space selects.
KQ-566 · DENSITY/GRID
Gaugeworks crew
Member
Role
Status
Rosa Amberlink
Field lead
Active
Ines Kettleby
Calibration
Active
Owen Marsh
Depot
Away
Priya Vance
Calibration
Active
Teo Bramhall
Yard
Invited
Halle Crane
Field lead
Paused
Nils Oberg
Depot
Active
June Rakes
Yard
Invited
comfortable · 0px tall
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/density-grid
Props
- rows
- { id: string; name: string; role: string; status: string }[]
- default —
- Rows in reading order. The id keys the row, so it survives a density change as the same row.
- density / defaultDensity
- "comfortable" | "cozy" | "compact"
- default "comfortable"
- Controlled or initial row density.
- onDensityChange
- (density: GridDensity) => void
- default —
- Fires when the switch moves, from the pointer or the keyboard.
- columns
- [string, string, string]
- default ["Member", "Role", "Status"]
- Column headers, left to right.
- label
- React.ReactNode
- default —
- Visible table label. Omit it and pass aria-label to name the table invisibly.
| Prop | Type | Default | Description |
|---|---|---|---|
| rows | { id: string; name: string; role: string; status: string }[] | — | Rows in reading order. The id keys the row, so it survives a density change as the same row. |
| density / defaultDensity | "comfortable" | "cozy" | "compact" | "comfortable" | Controlled or initial row density. |
| onDensityChange | (density: GridDensity) => void | — | Fires when the switch moves, from the pointer or the keyboard. |
| columns | [string, string, string] | ["Member", "Role", "Status"] | Column headers, left to right. |
| label | React.ReactNode | — | Visible table label. Omit it and pass aria-label to name the table invisibly. |