Skip to content

Commit 519ef1b

Browse files
bloveclaude
andauthored
docs(website): docs architecture + theming section (docs PR 1 of 4) (#60)
* docs(specs): pretable docs architecture design 25-page documentation site for pretable.ai/docs to replace the current 1-page stub. Topical IA with Diátaxis-hybrid shape (concept → recipes → reference) per section. Six top-level sections: Getting Started, Theming, Grid, Streaming (stub for v0.0.x), API Reference, Examples. Resolves the asymmetry where the @pretable/ui package README is more thorough than the website docs by lifting README content into a structured docs site and expanding it. IA aligns with user's other repos (angular-agent-framework, dawn — both use Getting Started / Concepts / Guides / Reference shape, both Next.js + MDX). Aligns with field conventions: Tailwind's "concept hub + token reference + escape hatch" pattern for theming, shadcn's CSS-variable contract pattern, AG Grid's per-feature concept→reference depth. Decomposed into 4 implementation PRs: - PR 1: Theming section + Concepts page + nav extension + /docs hub (the override story you flagged + supporting infrastructure) - PR 2: Grid section - PR 3: API Reference + Streaming stub + Examples gallery - PR 4: Polish + cross-references + package README updates Hand-authored MDX, third-person voice, code-first recipes. No auto-generation for v0.0.x. Reuses existing Callout + CodeBlock components from apps/website. One inline SVG architecture diagram on Theming Overview. Custom theme + Streaming examples deferred from v0.0.x until their authoring stories stabilize. Each PR gets its own writing-plans cycle when its turn comes. PR 1 starts immediately after this spec is approved. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(plans): pretable docs PR 1 — theming section + concepts 11-task plan covering the 9 new MDX pages + nav extension + /docs index hub refresh: - Task 1: Extend _nav.ts (1 section → 2) + refresh /docs hub - Task 2: Getting Started > Concepts page (mental-model overview) - Task 3: Theming Overview (concept page, ASCII-art layered diagram) - Task 4: Theming > Pick a theme (Excel vs Material 3) - Task 5: Theming > Override tokens (the override story) - Task 6: Theming > Light / dark switching - Task 7: Theming > Density switching - Task 8: Theming > Custom themes - Task 9: Theming > Tailwind v4 + CSS-in-JS - Task 10: Theming > Token reference (canonical 24-token table) - Task 11: Final verification (build + test + typecheck + prettier + visual sanity) Each MDX page has full content inline so the implementer subagent can transcribe rather than author. Prettier discipline on every commit step. ASCII-art diagram chosen over inline SVG to avoid JSX-in-MDX complexity for v0.0.x. Decided to drop the empty-sections-in-nav approach: Grid / Streaming / API Reference / Examples sections are added in PR 2 / PR 3 of the docs arc when their content lands. Sidebar feels "complete" via the /docs index hub's "Coming soon" copy. 10-11 commits in this PR depending on whether the spec/plan commits count. Each commit ships one user-visible page. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): extend nav + refresh /docs hub for theming section Extends apps/website/app/docs/_nav.ts from one section (Getting Started) to two (Getting Started, Theming). Adds the 8 theming nav entries pointing at pages that subsequent commits in this PR create. Also adds the Concepts entry under Getting Started. Refreshes apps/website/app/docs/page.mdx from the prior 8-line stub into a section-card hub. The hub describes the documented sections (Getting Started, Theming) + the deferred ones (Grid, Streaming, API Reference, Examples — landing in subsequent docs PRs). Honest about coverage rather than promising more than ships. Part 1 of pretable docs PR 1 (theming section + concepts). The content pages land in subsequent commits in this PR; the build passes here because Next.js doesn't validate href targets at build time. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Getting Started > Concepts page One-page mental-model overview of pretable's three-layer architecture: engine (@pretable/react), theming layer (@pretable/ui), streaming (deferred for v0.0.x). Documents the two-namespace coexistence pattern, the three runtime axes (theme, density, light/dark), and the pre-1.0 instability caveat. Cross-links to Theming Overview, Override tokens, Token reference, and the streaming overview (lands in PR 3 of the docs arc). Part 2 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming Overview (concept page) The theming model documented as three cooperating CSS layers: theme tokens (Layer 1), grid.css chrome selectors (Layer 2), consumer overrides (Layer 3). Includes an ASCII-art layered diagram (no SVG dependency) showing how the layers compose. Documents the 24-token contract grouped by purpose, the two attribute axes (data-theme, data-density), and the cascade order that resolves when consumer overrides + dark mode + density combine. Cross-links to all 7 theming sub-pages plus the Token reference. Part 3 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Pick a theme (recipe) Side-by-side description of Excel and Material 3 themes: visual identity, when to use each, import statements. Excel: gray/technical/ dense, light-only, Aptos Narrow 11pt, Excel-green active cell. Material 3: baseline scheme #6750A4, Roboto Flex, light + dark, 12dp medium shape, M3 surface tones. Build-time switch is a single import swap. Cross-links to override tokens, light/dark, density, custom themes. Part 4 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Override tokens (the override story) The override pattern explained: redefine --pretable-* values in your :root, cascade source-order wins because your stylesheet loads after the theme. No rebuild, no fork. Four worked examples: tweak one accent (brand alignment), swap entire palette (effectively a custom theme on top of Excel), change corner radius, override density values. Plus token-group taxonomy (surfaces / text / lines / state / accent / density / typography) and specificity tips. This is the "override story" the user flagged needs to be in /docs. Part 5 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Light / dark switching (recipe) Two patterns: React state-driven (user toggle button) and OS-respect (prefers-color-scheme media query). Both wire data-theme="dark" on <html> via a useEffect. Excel is light-only — flagged with a blockquote pointing at custom themes for consumers who need dark on Excel. Documents independent composition with data-density attribute and SSR considerations (cookie vs client-only). Part 6 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Density switching (recipe) Three-tier density toggle (compact / standard / spacious) wired via data-density attribute. Documents the per-theme natural default (Excel compact, Material standard), the engine bridge through useResolvedHeights + MutationObserver, prop-level override pattern, composition with light/dark, and a localStorage persistence example. Part 7 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Custom themes (recipe) Authoring a theme file from scratch: copy excel.css or material.css as a template, define all 24 --pretable-* tokens at :root, optionally add [data-theme="dark"] for dark mode and [data-density="..."] for non-default density tiers. Full code example for a custom brand theme. When-to-use table comparing override-at-:root vs. custom theme file vs. both. Part 8 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Tailwind v4 + CSS-in-JS (recipe) Two integration paths documented in one page (combined for v0.0.x; can split later if either grows). Tailwind v4: opt-in @pretable/ui/tailwind.css import registers --color-pt-* / --font-pt-* shortcuts via @theme. Utilities like bg-pt-bg-grid, text-pt-accent, font-pt-mono. Density and radius intentionally excluded (no per-element utility analog). CSS-in-JS: var(--pretable-*) works directly in styled-components, emotion, vanilla-extract, etc. Runtime resolution means tokens automatically reflect active theme + density + dark mode. Part 9 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> * docs(website): add Theming > Token reference (canonical 24-token table) Full reference for @pretable/ui's public theming contract. 24 tokens grouped: Surfaces (5), Text (3), Lines (3), State (4), Accent (1), Density (6), Typography (2). Each row: name, description, type (color / length / font), example value in Excel + Material 3 (light). Density tokens marked "engine reads?" — only --pretable-row-height and --pretable-header-height are read by JS; the other 22 are CSS-only. Plain markdown table for v0.0.x. If the contract grows past 30+ tokens later, upgrade to a sortable/filterable component. Stability disclaimer documents the pre-1.0 token-rename freedom. Part 10 of pretable docs PR 1. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
1 parent c1fb1d3 commit 519ef1b

13 files changed

Lines changed: 2946 additions & 2 deletions

File tree

‎apps/website/app/docs/_nav.ts‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@ export interface DocsNavSection {
1111
export const docsNav: DocsNavSection[] = [
1212
{
1313
title: "Getting Started",
14-
items: [{ title: "Install + first grid", href: "/docs/getting-started" }],
14+
items: [
15+
{ title: "Install + first grid", href: "/docs/getting-started" },
16+
{ title: "Concepts", href: "/docs/getting-started/concepts" },
17+
],
18+
},
19+
{
20+
title: "Theming",
21+
items: [
22+
{ title: "Overview", href: "/docs/theming" },
23+
{ title: "Pick a theme", href: "/docs/theming/pick-a-theme" },
24+
{ title: "Override tokens", href: "/docs/theming/override-tokens" },
25+
{ title: "Light / dark", href: "/docs/theming/light-dark" },
26+
{ title: "Density", href: "/docs/theming/density" },
27+
{ title: "Custom themes", href: "/docs/theming/custom-themes" },
28+
{
29+
title: "Tailwind + CSS-in-JS",
30+
href: "/docs/theming/tailwind-css-in-js",
31+
},
32+
{ title: "Token reference", href: "/docs/theming/token-reference" },
33+
],
1534
},
1635
];
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: Concepts
3+
description: The mental model behind Pretable — a headless engine, a theming layer, and a streaming pipeline that compose through CSS variables and React hooks.
4+
---
5+
6+
# Concepts
7+
8+
Pretable is built around three layers. Understanding their boundaries makes the rest of the docs easier to navigate.
9+
10+
## The engine + theming split
11+
12+
`@pretable/react` is the **engine**. It handles row virtualization, column layout, focus and selection state, sort and filter dispatch, and the data attributes (`[data-pretable-*]`) that mark every interactive element. The engine is structurally pure — its inline styles handle position, height, and z-index, but no colors, padding, fonts, or borders.
13+
14+
`@pretable/ui` is the **theming layer**. It ships CSS files: theme files (`themes/excel.css`, `themes/material.css`) declare `--pretable-*` design tokens at `:root`; `grid.css` is a selector-based skin that targets the engine's data attributes and resolves the tokens. There's no JavaScript theme builder; everything is CSS.
15+
16+
The two packages cooperate through a documented contract: the engine emits known data attributes, the theming layer styles them. Either side can be replaced without forking the other — you can ship `@pretable/ui` with a different design system, or use `@pretable/react` with hand-rolled CSS, and both still work.
17+
18+
## Two CSS-variable namespaces
19+
20+
Pretable uses one CSS-variable namespace exclusively: `--pretable-*`. All 24 public tokens live there. See the [token reference](/docs/theming/token-reference) for the full list.
21+
22+
Your application has its own namespace — whatever brand tokens you already use, like `--brand-*`, `--app-*`, or your design system's prefix. The two never collide because they're prefix-disjoint. You can theme the grid with Material 3 while your surrounding marketing site uses your own brand tokens, and there's no leakage either direction.
23+
24+
## Three runtime axes
25+
26+
Pretable's theming surface has three axes that can change at runtime:
27+
28+
- **Theme** — pick `excel.css` or `material.css` at build time by importing one. Switch between themes by swapping which CSS file is active (or by setting CSS variables manually if you want a hybrid).
29+
- **Density** — toggle `data-density="compact"`, `data-density="standard"`, or `data-density="spacious"` on `<html>` to switch row heights, padding, and font sizes. The engine reads the new heights from CSS via `MutationObserver` and re-renders.
30+
- **Light / dark** — toggle `data-theme="dark"` on `<html>` to activate Material's dark variant. Excel is light-only by design.
31+
32+
All three compose. `<html data-theme="dark" data-density="spacious">` gives you Material dark in spacious density. CSS specificity handles the cascade; no JavaScript coordination needed beyond the attribute toggles.
33+
34+
## Streaming
35+
36+
Pretable can render rows that arrive over the network — JSON streams, transactions API, server-sent events. The streaming pipeline is implemented but the public API is in flux for v0.0.x. See [Streaming Overview](/docs/streaming) for the current state, or browse `apps/streaming-demo/` in the repo for working code.
37+
38+
## Pre-1.0 caveat
39+
40+
> Pretable ships at version 0.0.x. Token names in `@pretable/ui` may rename or remove in any patch release. The engine API in `@pretable/react` is more stable but not frozen. Check the changelog before upgrading.
41+
42+
## Where to go next
43+
44+
- [Theming Overview](/docs/theming) — the customization surface, in detail.
45+
- [Override tokens](/docs/theming/override-tokens) — change individual `--pretable-*` values without forking a theme.
46+
- [Token reference](/docs/theming/token-reference) — the canonical list of all 24 tokens.
47+
48+
For the architectural rationale (why CSS variables, why density-coupled-to-theme, etc.), the design spec at `docs/superpowers/specs/2026-05-02-pretable-docs-architecture-design.md` has the why behind the what.

‎apps/website/app/docs/page.mdx‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@
22

33
Pretable is a React grid built around a deterministic engine. Selection survives filters; scroll stays at 60fps with 500k rows.
44

5-
Start with the [getting-started guide](/docs/getting-started) for installation and your first grid. More guides land in future releases.
5+
## Sections
6+
7+
### Getting Started
8+
9+
[Install + first grid](/docs/getting-started) walks you through `npm install` to a rendered three-column, five-row grid in five minutes. [Concepts](/docs/getting-started/concepts) is a one-page mental-model overview of the engine + theming + streaming layers — read it before diving into customization.
10+
11+
### Theming
12+
13+
[Theming](/docs/theming) covers the full customization surface: pick a prebuilt theme (Excel or Material 3), override individual `--pretable-*` tokens, switch light/dark and density at runtime, and author your own themes from a template. The [token reference](/docs/theming/token-reference) is the canonical 24-token table.
14+
15+
### Coming soon
16+
17+
The rest of the docs surface lands in subsequent releases:
18+
19+
- **Grid** — the engine API: columns, rows, selection, focus, sort, filter, density helpers.
20+
- **Streaming** — transactions API and JSON streaming.
21+
- **API Reference** — `PretableGrid` props, column types, theme token contract, density helpers.
22+
- **Examples** — live, copy-pasteable patterns: basic table, light/dark switcher, density picker.
23+
24+
## Source
625

726
The codebase, including this site, lives at [github.com/cacheplane/pretable](https://github.com/cacheplane/pretable).
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
title: Custom themes
3+
description: Author a theme file from scratch — define all 24 tokens at :root, optionally add density and dark-mode variants.
4+
---
5+
6+
# Custom themes
7+
8+
When overrides grow beyond a handful of tokens, switch from override-on-top-of-existing to authoring a theme file from scratch. The contract is straightforward: define all 24 `--pretable-*` tokens at `:root`. Optionally add `[data-density="..."]` and `[data-theme="dark"]` blocks for runtime variants.
9+
10+
## Start from a template
11+
12+
Copy `excel.css` or `material.css` from `node_modules/@pretable/ui/themes/` into your project. They're hand-readable CSS — no preprocessing, no build step needed. Rename the file (e.g., `themes/brand.css`) and tweak the values.
13+
14+
```css
15+
/* themes/brand.css */
16+
:root {
17+
/* Surfaces */
18+
--pretable-bg-grid: #ffffff;
19+
--pretable-bg-grid-alt: #fafafa;
20+
--pretable-bg-header: #f0f0f0;
21+
--pretable-bg-toolbar: #f0f0f0;
22+
--pretable-bg-tooltip: #ffffff;
23+
24+
/* Text */
25+
--pretable-text-cell: #1a1a1a;
26+
--pretable-text-header: #404040;
27+
--pretable-text-dim: #6a6a6a;
28+
29+
/* Lines */
30+
--pretable-rule: #d8d8d8;
31+
--pretable-rule-strong: #a0a0a0;
32+
--pretable-radius: 4px;
33+
34+
/* State */
35+
--pretable-bg-hover: #f5f5f5;
36+
--pretable-bg-selected: rgba(255, 87, 34, 0.1);
37+
--pretable-text-selected: #1a1a1a;
38+
--pretable-focus-ring: #ff5722;
39+
40+
/* Accent */
41+
--pretable-accent: #ff5722;
42+
43+
/* Density */
44+
--pretable-row-height: 28px;
45+
--pretable-header-height: 32px;
46+
--pretable-cell-padding-x: 8px;
47+
--pretable-cell-padding-y: 4px;
48+
--pretable-font-size-cell: 14px;
49+
--pretable-font-size-header: 12px;
50+
51+
/* Typography */
52+
--pretable-font-sans:
53+
"Inter", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
54+
--pretable-font-mono: "JetBrains Mono", ui-monospace, Consolas, monospace;
55+
}
56+
```
57+
58+
Import your theme file instead of (or alongside) the prebuilt themes:
59+
60+
```css
61+
@import "./themes/brand.css";
62+
@import "@pretable/ui/grid.css";
63+
```
64+
65+
## Add a dark-mode variant
66+
67+
If your theme should have dark mode, add a `[data-theme="dark"]` block. Override only the color tokens (density and typography typically inherit from light):
68+
69+
```css
70+
[data-theme="dark"] {
71+
/* Surfaces */
72+
--pretable-bg-grid: #1a1a1a;
73+
--pretable-bg-grid-alt: #1f1f1f;
74+
--pretable-bg-header: #2a2a2a;
75+
--pretable-bg-toolbar: #2a2a2a;
76+
--pretable-bg-tooltip: #2a2a2a;
77+
78+
/* Text */
79+
--pretable-text-cell: #e8e8e8;
80+
--pretable-text-header: #c0c0c0;
81+
--pretable-text-dim: #888888;
82+
83+
/* Lines */
84+
--pretable-rule: #3a3a3a;
85+
--pretable-rule-strong: #585858;
86+
87+
/* State */
88+
--pretable-bg-hover: #252525;
89+
--pretable-bg-selected: rgba(255, 138, 101, 0.15);
90+
--pretable-text-selected: #ffffff;
91+
--pretable-focus-ring: #ff8a65;
92+
93+
/* Accent */
94+
--pretable-accent: #ff8a65;
95+
}
96+
```
97+
98+
Toggle `data-theme="dark"` on `<html>` to activate. See [Light / dark switching](/docs/theming/light-dark) for the React wiring.
99+
100+
## Add density variants
101+
102+
If you want compact/standard/spacious tiers, add explicit blocks for the non-default tiers. Don't redefine the natural default — let `:root` handle that.
103+
104+
If your `:root` is the standard tier:
105+
106+
```css
107+
[data-density="compact"] {
108+
--pretable-row-height: 22px;
109+
--pretable-header-height: 26px;
110+
--pretable-cell-padding-x: 6px;
111+
--pretable-cell-padding-y: 2px;
112+
--pretable-font-size-cell: 13px;
113+
--pretable-font-size-header: 11px;
114+
}
115+
116+
[data-density="spacious"] {
117+
--pretable-row-height: 40px;
118+
--pretable-header-height: 48px;
119+
--pretable-cell-padding-x: 16px;
120+
--pretable-cell-padding-y: 12px;
121+
--pretable-font-size-cell: 14px;
122+
--pretable-font-size-header: 13px;
123+
}
124+
```
125+
126+
Skip the `[data-density="standard"]` block since `:root` already provides those values. CSS handles the rest — when the user sets `data-density="standard"`, no rule matches and the cascade falls back to `:root`.
127+
128+
## Validate against the contract
129+
130+
Pretable doesn't enforce that custom themes define all 24 tokens — if you skip one, that token resolves to its default value (which depends on the engine's fallback) or to whatever else is in scope. The smoke test in `@pretable/ui` verifies that each shipped theme defines every documented token; if you want similar validation for your custom theme, copy that test pattern.
131+
132+
The full token list is in [Token reference](/docs/theming/token-reference).
133+
134+
## When to ship a custom theme as a separate file vs. override at `:root`
135+
136+
| Approach | When to use |
137+
| --------------------------------------- | ---------------------------------------------------------------------- |
138+
| Override individual tokens at `:root` | 1-5 tokens differ from a prebuilt theme. Stay close to Excel/Material. |
139+
| Author a custom theme file from scratch | Most or all tokens differ. You want a dedicated brand theme. |
140+
| Both | Custom theme as the base, occasional overrides for dark-only tweaks. |
141+
142+
For most apps, overriding individual tokens at `:root` is sufficient. Switch to a custom theme file when the override block grows past ~10 tokens or when you want to share your theme across multiple apps.
143+
144+
## Where to go next
145+
146+
- [Override tokens](/docs/theming/override-tokens) — when single-token overrides are enough.
147+
- [Token reference](/docs/theming/token-reference) — the canonical 24-token list.
148+
- [Light / dark switching](/docs/theming/light-dark) — toggle the dark variant of your custom theme.
149+
- [Density switching](/docs/theming/density) — runtime tier toggle for your custom density blocks.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: Density switching
3+
description: Runtime row height, padding, and font size toggle via data-density attribute. Engine reads new values via MutationObserver and re-renders.
4+
---
5+
6+
# Density switching
7+
8+
Pretable supports three density tiers — compact, standard, spacious — selected by the `data-density` attribute on `<html>`. Both Excel and Material define their own values per tier; switching is a single attribute toggle.
9+
10+
## How it composes
11+
12+
Each theme's natural default lives at `:root`:
13+
14+
- **Excel** defaults to compact (20px rows). `[data-density="standard"]` and `[data-density="spacious"]` blocks override for tighter or roomier modes.
15+
- **Material** defaults to standard (48px rows). `[data-density="compact"]` and `[data-density="spacious"]` blocks override.
16+
17+
When the consumer sets `data-density="standard"` on `<html>` while Excel is loaded, the standard block wins (more specific selector than `:root`). When the consumer removes the attribute, the standard block stops matching and the `:root` (compact) values reassert.
18+
19+
> Density values are theme-coupled by design. Excel's "compact" (20px row) is tighter than Material's "compact" (40px row) because each theme's identity includes its own density character. Picking compact in Excel and compact in Material gives you different absolute heights — the relationship is what's preserved across themes.
20+
21+
## React state-driven
22+
23+
Same pattern as light/dark — hold density in state, sync to the DOM:
24+
25+
```tsx
26+
import { useEffect, useState } from "react";
27+
28+
type Density = "compact" | "standard" | "spacious";
29+
30+
export function DensityPicker({
31+
density,
32+
onChange,
33+
}: {
34+
density: Density;
35+
onChange: (density: Density) => void;
36+
}) {
37+
useEffect(() => {
38+
document.documentElement.dataset.density = density;
39+
}, [density]);
40+
41+
return (
42+
<div role="radiogroup" aria-label="Row density">
43+
<button onClick={() => onChange("compact")}>Compact</button>
44+
<button onClick={() => onChange("standard")}>Standard</button>
45+
<button onClick={() => onChange("spacious")}>Spacious</button>
46+
</div>
47+
);
48+
}
49+
```
50+
51+
Wrap your app with a `<DensityPicker density={...} onChange={...} />` and hold the state in your app's root or persist it to localStorage.
52+
53+
## The engine bridge
54+
55+
Two density tokens are read by the engine in JavaScript, not just by CSS:
56+
57+
- `--pretable-row-height` — used by the row virtualizer to compute `top` positions.
58+
- `--pretable-header-height` — used to position the sticky header and compute body viewport height.
59+
60+
The engine reads these via the `useResolvedHeights` hook (in `@pretable/react`), which subscribes to attribute changes on `<html>` via `MutationObserver`. When you flip `data-density`, the engine re-renders the grid with new heights automatically — no need to pass `rowHeight` or `headerHeight` props from your component.
61+
62+
If you want to override the heights at the component level (e.g., a single grid uses spacious while the rest of the app respects user preference), pass props:
63+
64+
```tsx
65+
<PretableGrid rows={rows} columns={columns} rowHeight={56} headerHeight={64} />
66+
```
67+
68+
Numeric props win over CSS-resolved values. See [Density helpers](/docs/grid/density-helpers) for the full hook API (lands in PR 2 of the docs).
69+
70+
## Composition with light/dark
71+
72+
Density and theme variants are independent. `<html data-theme="dark" data-density="compact">` gives you Material dark in compact density. The cascade resolves cleanly because `[data-theme="dark"]` overrides only colors and `[data-density="compact"]` overrides only density tokens.
73+
74+
## Persisting density across reloads
75+
76+
Most apps persist density to localStorage:
77+
78+
```tsx
79+
import { useEffect, useState } from "react";
80+
81+
type Density = "compact" | "standard" | "spacious";
82+
83+
function readDensity(): Density {
84+
if (typeof window === "undefined") return "standard";
85+
const stored = window.localStorage.getItem("pretable-density");
86+
return stored === "compact" || stored === "spacious" ? stored : "standard";
87+
}
88+
89+
export function useDensity() {
90+
const [density, setDensity] = useState<Density>(readDensity);
91+
92+
useEffect(() => {
93+
document.documentElement.dataset.density = density;
94+
window.localStorage.setItem("pretable-density", density);
95+
}, [density]);
96+
97+
return [density, setDensity] as const;
98+
}
99+
```
100+
101+
Use the hook in your density picker:
102+
103+
```tsx
104+
const [density, setDensity] = useDensity();
105+
return <DensityPicker density={density} onChange={setDensity} />;
106+
```
107+
108+
## Where to go next
109+
110+
- [Override tokens](/docs/theming/override-tokens) — change density values themselves, not just which tier is active.
111+
- [Light / dark switching](/docs/theming/light-dark) — composes with density.
112+
- [Density helpers](/docs/grid/density-helpers) — `useResolvedHeights` and `getDensityHeights` API (PR 2 of the docs).

0 commit comments

Comments
 (0)