Grid Density helpers

Density helpers

Read density tokens (compact, standard, spacious) into JavaScript at runtime.

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.

ts
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:

ts
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:

VariableFallback
--pretable-row-height32
--pretable-header-height52

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 usePretable, 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.

ts
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

SituationUse
React component that should re-render on density/theme changeuseResolvedHeights from @pretable/react
Vanilla JS / non-React utilitygetDensityHeights from @pretable/ui
One-shot read at component mount (no reactivity needed)Either; getDensityHeights is slightly leaner
Custom rendering with usePretableuseResolvedHeights (matches the engine's reads)

Where to go next