Density

Density is the cross-cutting knob that retunes padding, gaps and control heights without touching color or radius. comfortable is the marketing-first default; compact is the application-UI preset.

Two densities#

The same Card, rendered comfortable (the default) and compact. Only spacing and title scale change - corners stay the brand 16px radius.

Comfortable
Generous spacing for marketing.
p-6 · gap-6 · text-lg title.
Compact
Tight, dense application UI.
p-4 · gap-4 · text-base title.

On a real block#

Density isn’t a one-component knob. Here it drives a whole sign-in block: toggle it and the card retunes all at once - comfortable opens the padding, gaps and title up for a roomier marketing feel, compact tightens everything for dense app UI.

Welcome back

Sign in to your account to continue.

Forgot password?

Don't have an account? Sign up

Application-UI spec#

The compact preset, modelled on a dense dashboard: 16px padding and gaps, 1rem card titles, 14px muted descriptions, and controls that aren’t too tall.

comfortablecompact
Card padding / gapp-6 · gap-6p-4 · gap-4 (16px)
Card titletext-lgtext-base (1rem)
Card descriptiontext-sm mutedtext-sm muted
Button height (default md)h-9 (36px)h-9 (36px)
Dialog padding / gapp-6 · gap-4p-4 · gap-3
Tabs pillrounded-xl p-1rounded-lg p-0.5

Set it once for a subtree#

Wrap an app shell in DensityProvider and every nested Koala component tightens up - no per-instance props. Resolution precedence is explicit prop > nearest provider > comfortable, so any component can opt back out.

app-shell.tsxTSX
import { DensityProvider } from "@/lib/density"export function Dashboard({ children }) {  // Everything inside renders compact unless a component sets density itself.  return <DensityProvider density="compact">{children}</DensityProvider>}
Payout threshold
Minimum balance before a payout triggers.
$2,500.00

Which components honor density#

Density reaches across the library: controls (Button, Select, Tabs, Pagination), surfaces (Card, Dialog, Drawer), data display (Stat, List, Description List, Data Table) and the form blocks all retune. Avatar and Badge opt out by design - they already own explicit pixel size scales, so a spacing axis would be redundant.

Reading density makes a component a client component. Card, Dialog and Tabs already were; Button is now "use client" too, so it can participate in provider-driven density.