useDocumentClassOutput
Returns the merged html and body attributes every useDocumentClass() call has registered, as React props ready to spread.
import { useDocumentClassOutput } from '@salla.sa/twilight-theme-engine/providers';In plain words
Components can ask for classes and attributes on <body> and <html> with useDocumentClass(). The provider merges all those requests, and useDocumentClassOutput() gives you the merged result as two objects of React props (className instead of class).
Signature
function useDocumentClassOutput(): {
bodyAttrs: Record<string, string>; // { className: 'salla-raed color-mode-light rtl …' }
htmlAttrs: Record<string, string>; // { lang: 'ar', dir: 'rtl' }
}Try it live
import { useDocumentClass } from '@salla.sa/twilight-theme-engine/hooks/useDocumentClass';
import { useDocumentClassOutput } from '@salla.sa/twilight-theme-engine/providers';
// A page asks for a body class while it is mounted.
export function ProductPage() {
useDocumentClass({ body: { class: 'playground-demo' } });
return <main>…</main>;
}
// Anything below TwilightProvider can read the merged result.
export function BodyClassDebug() {
const { bodyAttrs } = useDocumentClassOutput();
return <pre>{bodyAttrs.className}</pre>;
}
Example
import { useDocumentClassOutput } from '@salla.sa/twilight-theme-engine/providers';
export function BodyClassDebug() {
const { bodyAttrs, htmlAttrs } = useDocumentClassOutput();
return <pre>{JSON.stringify({ bodyAttrs, htmlAttrs }, null, 2)}</pre>;
}
How it behaves
Merge rules: every
classvalue is split, joined and de-duplicated; any other attribute takes the value of the last registration; empty strings are skipped.It subscribes to the provider's store (
useSyncExternalStore), so it renders again whenever a registration changes. With noDocumentClassProviderabove it, both objects are empty.The provider applies the attributes to the real
<body>and<html>itself, in an effect; this hook only reads them.
Gotchas
Its result is empty in the server render.
useDocumentClass()registers in an effect, and effects never run on the server, so spreading the result onto<html>or<body>adds nothing to the HTML; docs/20-document-class.md says this hook "makes SSR work". For attributes the server must send, setlanganddirfromgetTwilightContext()as the reference theme does, or use routestaticData.documentAttrswithuseAttrs()from/tanstack.Because the server and the browser disagree, render its output only after hydration.
Related
Low-level access to the store behind useDocumentClass(): register or remove an html and body descriptor under an id you choose.
DocumentClassProviderCollects every useDocumentClass() request in its tree and applies the merged classes and attributes to the real body and html elements.
TwilightProviderThe component a theme mounts once around its pages; it shares the store, theme, language and navigation with everything inside it.