title: Density helpers description: useResolvedHeights (React hook) and getDensityHeights (vanilla JS) — read --pretable-row-height and --pretable-header-height into JavaScript.
Density helpers
Two functions read density values into JavaScript. They live in different packages because they target different consumers.
useResolvedHeights — React hook
Lives in @pretable/react. Reads --pretable-row-height and --pretable-header-height from <html>'s computed style. Subscribes to attribute changes via MutationObserver so the values stay reactive when consumers flip data-density or data-theme.
import { useResolvedHeights } from "@pretable/react";
const { rowHeight, headerHeight } = useResolvedHeights();Both return values are numbers (not strings). The hook re-renders the component when either CSS variable changes.
Optional numeric overrides
If you want JS-side control (e.g., reading from a settings store), pass numbers as arguments:
const { rowHeight, headerHeight } = useResolvedHeights(
rowHeightOverride,
headerHeightOverride,
);Numeric arguments win over CSS-resolved values. Pass undefined to defer to CSS for that value.
Fallback values
If neither argument nor CSS variable resolves to a <number>px value, the hook returns built-in fallbacks:
| Variable | Fallback |
| -------------------------- | -------- |
| --pretable-row-height | 32 |
| --pretable-header-height | 52 |
The header-height fallback matches the legacy HEADER_HEIGHT constant the engine used before the theming bridge landed, so unmigrated apps see no behavior change. The row-height fallback is conservative (between Excel's 20px compact and Material's 48px standard).
SSR safety
The hook is SSR-safe. On the server (where document is undefined), the snapshot returns the fallback values without DOM access. After hydration on the client, the MutationObserver subscribes and the hook returns CSS-resolved values.
Used internally
<Pretable> and <PretableSurface> (private) both use useResolvedHeights to compute the body viewport height (viewportHeight - headerHeight) and to size the sticky header. When you render with usePretableModel, you typically call useResolvedHeights() yourself to compute the same — see the example in Custom rendering.
getDensityHeights — vanilla JS snapshot
Lives in @pretable/ui. A non-React snapshot — same read logic but without useSyncExternalStore or MutationObserver.
import { getDensityHeights } from "@pretable/ui";
const { rowHeight, headerHeight } = getDensityHeights();Returns the same {rowHeight, headerHeight} shape as useResolvedHeights but does NOT subscribe to changes. Call it once to read current values.
Use this when:
- You're not in a React component (e.g., a vanilla TypeScript utility, a non-React framework, a Node script that needs the values from a DOM snapshot)
- You only need a one-shot read at a specific moment (e.g., page load)
- You want to avoid the React hook's subscription cost (microscopic, but real)
Which to use
| Situation | Use |
| ------------------------------------------------------------- | ------------------------------------------------- |
| React component that should re-render on density/theme change | useResolvedHeights from @pretable/react |
| Vanilla JS / non-React utility | getDensityHeights from @pretable/ui |
| One-shot read at component mount (no reactivity needed) | Either; getDensityHeights is slightly leaner |
| Custom rendering with usePretableModel | useResolvedHeights (matches the engine's reads) |
Where to go next
- Theming > Density switching — recipe for wiring
data-densityfrom React state. - Custom rendering — using
useResolvedHeightswithusePretableModel. - API reference — full type signatures.