Koder Design — Density modes
themes specs/themes/density.kmd
Three canonical page-level density modes (compact / default / comfortable) with token deltas, accessibility floor, persistence pattern, and multi-tenant override rules. Density scales Verge spacing + typography tokens uniformly through CSS custom property cascade, so consumers opt in through a single attribute on the document root.
Corpo da especificação
Koder Design — Density modes
Density is the global rhythm a Koder surface ships with. Three canonical
modes are supported: compact, default, comfortable. The mode
sets data-density on <html>; Verge tokens cascade through CSS custom
properties so every component picks up the new rhythm without per-call
overrides. Power-user tools default to compact; touch tablets opt
in to comfortable; public landings stay on default.
This is parity work with Fluent 2 (Microsoft Design), Material 3 ("Density"
in the Spacing track), and Carbon ("Spacing scale + tokens"). The
ratio −20% / 0% / +20% matches Fluent 2's spacing track to make a
cross-design-system port mechanical.
R1 — When to use which mode
- compact (default for Koder admin/data-dense surfaces): Outlook-class inboxes, Excel-class grids, log viewers, dev tools, file managers, Flow's repo browser. Power users on desktop with a mouse.
- default (default everywhere else): landing pages, marketing, docs (KDS site), product home, settings, dialogs, onboarding. Reading comfort + density balance.
- comfortable: touch tablets, kiosks, TV (10-foot UI), accessibility user preference. Larger hit targets, more breathing room.
The page picks one mode as default; user override goes into the Settings drawer (see R4). Per-component override is out of scope of this spec — see § Não-escopo.
R2 — Token deltas
Density multiplies Verge tokens through a single multiplier custom
property --kds-density-scale. Compact = 0.8, default = 1,
comfortable = 1.2. Tokens that read through the scale automatically
respect the mode:
| Token family | Compact | Default | Comfortable |
|---|---|---|---|
--kds-space-* | × 0.8 | × 1 | × 1.2 |
--kds-line-height-tight | × 0.95 | × 1 | × 1.05 |
| Form control min-height | 32 px | 40 px | 48 px |
| Button padding (Y) | 6 px | 8 px | 10 px |
| List row padding | 4 px | 8 px | 12 px |
Typography sizes from specs/fonts/typography.kmd stay constant — only
spacing and component minimum dimensions scale. Rationale: changing
type sizes per density mode breaks visual hierarchy and AAA contrast
spot-checks done at the canonical scale.
R3 — Accessibility floor
The comfortable mode is the WCAG 2.2 baseline for touch targets:
form-control minimum-height never drops below 44 px (per
specs/koder-app/behaviors.kmd § Tap targets). Compact is desktop-only
and intentionally violates the touch target floor; surfaces that ship
compact MUST also ship a "tap target ≥ 44 px" branch behind
@media (pointer: coarse) so a touch device viewing a compact surface
gets the comfortable rhythm anyway.
@media (pointer: coarse) {
[data-density="compact"] { --kds-density-scale: 1.2; }
}
This is mandatory; failure to ship it fails T3 below.
R4 — Persistence
User override persists in localStorage["koder.density"] with values
compact | default | comfortable. The anti-flash script in the page
shell reads the key and writes data-density on <html> before first
paint — same pattern as koder.theme from
specs/themes/light-dark.kmd § Persistence.
Settings drawer surfaces a 3-segment control (Compact / Default /
Comfortable) below the Theme group, sharing the same visual treatment
(button[role="radio"] set, aria-pressed). The drawer writes the
new value to localStorage and data-density on <html> immediately.
A page MAY ship a per-page initial density via the density query
parameter (?density=compact) — useful for marketing previews that
demonstrate the surface at a specific rhythm. Query overrides persist
only for the session (sessionStorage); the persisted localStorage
choice is not mutated.
R5 — Multi-tenant override
Tenants on the Koder platform MAY pin density per workspace via the
workspace.density_default setting. When set, the platform shell
injects the override before the anti-flash script so the user's
localStorage choice still wins (R4 takes precedence). Tenants MUST
NOT lock the override; a tenant that genuinely needs a fixed density
(public kiosk) ships its own surface, not a tenant-platform setting.
Tests
| ID | Test |
|---|---|
| T1 | Setting data-density="compact" on <html> reduces resolved --kds-space-md by 20% from default. |
| T2 | Setting data-density="comfortable" increases it by 20%. |
| T3 | @media (pointer: coarse) block forces comfortable rhythm regardless of data-density attribute. |
| T4 | localStorage koder.density set to compact survives reload (anti-flash applies before paint). |
| T5 | Settings drawer 3-segment control reflects the current value via aria-pressed. |
| T6 | Per-component overrides do NOT exist — grep for [data-density] inside .koder-* components is 0. |
Não-escopo
- Per-component density override (compact button inside default form). Density is page-level by spec; tools that need a denser sub-region ship a custom token scope.
- Touch-detect auto-density. Spec defaults to
default; touch devices opt in to comfortable via Settings or via the@media (pointer: coarse)branch (R3). Automatic OS detection would conflict with the three-way persisted user choice.
References
specs/themes/light-dark.kmd§ Persistence — anti-flash patternspecs/themes/verge.kmd§ R4 — token map this scalesspecs/fonts/typography.kmd— type scale stays constantspecs/koder-app/behaviors.kmd§ Tap targets — touch floor- Fluent 2 density tracks · Material 3 spacing scale · Carbon spacing