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:

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