Density
Three density modes — compact, normal, and comfortable — let product teams tune information density to their context. A single data attribute on the root element rewires all spacing and height tokens simultaneously.
Modes
data-density="compact"Compact
Data-dense UIs: admin dashboards, data grids, developer tools. Maximum information per screen with reduced padding and smaller controls.
data-density="normal"Normal
The default. Balances readability and density for general-purpose product UIs. This is what all Sitka components render at out of the box.
data-density="comfortable"Comfortable
Consumer apps, onboarding flows, marketing pages. More breathing room for non-expert audiences or touch-primary interfaces.
Token scale
All eight density tokens are CSS custom properties set on :root (normal defaults) and overridden by the data-density attribute.
| Token | Compact | Normal | Comfortable | Use |
|---|---|---|---|---|
| --density-space-xs | 2px | 4px | 6px | Icon gaps, chip insets |
| --density-space-sm | 6px | 8px | 12px | Inline element gaps |
| --density-space-md | 8px | 12px | 16px | Component padding |
| --density-space-lg | 12px | 16px | 20px | Row padding, card insets |
| --density-space-xl | 16px | 24px | 32px | Section separation |
| --density-h-sm | 24px | 28px | 32px | Small control height |
| --density-h-md | 30px | 36px | 40px | Default control height |
| --density-h-lg | 36px | 44px | 48px | Large control height |
Component impact
| Component | Compact | Normal | Comfortable |
|---|---|---|---|
| Button (md) | 30px height | 36px height | 40px height |
| Input | 30px height | 36px height | 40px height |
| Table row | 12px v-padding | 16px v-padding | 20px v-padding |
| List item | 6px v-padding | 8px v-padding | 12px v-padding |
| Card | 12px padding | 16px padding | 20px padding |
| Sidebar item | 6px v-padding | 8px v-padding | 12px v-padding |
Usage
<!-- Apply to <html> to affect the whole app -->
<html data-density="compact">
<!-- Or scope to a subtree -->
<div data-density="comfortable">
<YourDataTable />
</div>"use client";
import { createContext, useContext, useEffect } from "react";
type Density = "compact" | "normal" | "comfortable";
const DensityCtx = createContext<Density>("normal");
export function DensityProvider({
density = "normal",
children,
}: {
density?: Density;
children: React.ReactNode;
}) {
useEffect(() => {
document.documentElement.dataset.density =
density === "normal" ? "" : density;
}, [density]);
return (
<DensityCtx.Provider value={density}>
{children}
</DensityCtx.Provider>
);
}
export const useDensity = () => useContext(DensityCtx);Authoring density-aware components
.my-row {
padding-block: var(--density-space-md);
padding-inline: var(--density-space-lg);
min-height: var(--density-h-md);
gap: var(--density-space-sm);
}Reference density tokens instead of hardcoded values. When the density attribute changes, every consuming component reflows automatically with no JavaScript required.
Guidelines
- →Choose one density mode per product surface — mixing modes within a single view creates visual inconsistency.
- →Compact mode is appropriate for power-user tooling (data grids, admin panels, developer dashboards).
- →Comfortable mode suits consumer onboarding, marketing microsites, and touch-primary mobile contexts.
- →Normal is the default for general-purpose SaaS product UI — most Sitka components are sized for this mode.
- →When in doubt, ship normal and add a user preference toggle later. Density changes are additive and non-breaking.