Density
How much room a row, a control and an hour take: comfortable by default, compact chosen on any element.
The tokens
Five tokens, only the ones the dense screen proves. Comfortable is the default; compact is chosen with data-density="compact" on any element, not only :root — the custom properties inherit, so a part of a page can be compact while the rest stays comfortable. A region inside a compact one returns to comfortable with data-density="comfortable".
Comfortable is what is drawn for the row, its header and the button; the hour is 80 for the drawn 81. The drawn field is 48 at its default size and the drawn navigation item 48, where density/control and density/nav-item give 40: this page said comfortable was what is drawn (corrected 2026-09-24, fidelity audit), and which height stands is still to be decided.
| Token | Comfortable | Compact | Read by |
|---|---|---|---|
| density/control | 40px | 32px | A control’s height when no size is passed: Button, Input, Select, NativeSelect, Combobox, DatePicker |
| density/row | 72px | 48px | A Table row |
| density/row-header | 44px | 36px | A Table header row |
| density/hour | 80px | 64px | An hour in the Scheduler; a quarter of it is a card’s floor |
| density/nav-item | 40px | 32px | An item in the SideNav and the SideNavSecondary |
Choosing
Compact where a person scans many rows with a pointer — a dense Table, a packed Scheduler, a long SideNav — and comfortable everywhere else, which is most of a product. An explicit size on a control, and the Table’s own explicit density prop, keep winning over the token: with neither attribute, nothing changes from today.
Touch
Compact does not apply under a finger. Inside @media (pointer: coarse) the compact block restates the comfortable values, so a control stays 40px and a row 72px even with data-density="compact" set. 32px passes WCAG 2.5.8’s 24px floor, but under a thumb at 375px it reads small, and density is for the pointer and the keyboard, not the touchscreen.
Try it
The same Button, Input, Select and Scheduler slice, drawn twice: once at rest, and once inside data-density="compact". None of the controls take a size — every measurement below comes from the attribute alone.
Comfortable
Compact
The client Table takes no density prop either, but it needs its own full width to prove it: below the Table’s own 258px threshold it loses its Appointment column, which is correct — and exactly what the panels above would force on it. Stacked instead, its row is 72px in the first and 48px in the second.
Comfortable
| Client | Appointment |
|---|---|
| Maya Costa | Assessment |
| Joaquim Okafor | Follow-up |
| Aisha Nguyen | Sports massage |
Compact
| Client | Appointment |
|---|---|
| Maya Costa | Assessment |
| Joaquim Okafor | Follow-up |
| Aisha Nguyen | Sports massage |
In code
<div data-density="compact">
{/* Button, Input, Select, Table and Scheduler inside read the compact values. */}
</div>
// Tailwind: the density utilities read the token where they are used.
<div className="h-density-row">…</div>In Figma
A fourth collection, Alpenglow Density, two modes, Comfortable and Compact, one variable per token above, each with scopes set to WIDTH_HEIGHT so a designer sees only the properties it applies to.