Skip to content
Twilight React Playground
ثيم رائدaren

useDocumentClassContext

hookAdvancedbrowserlive demo

Low-level access to the store behind useDocumentClass(): register or remove an html and body descriptor under an id you choose.

import { useDocumentClassContext } from '@salla.sa/twilight-theme-engine/providers';

In plain words

useDocumentClass() is the friendly way to put classes on <body>. Underneath, it calls a small store with register(id, descriptor) and unregister(id).

This hook returns that store, or null without a provider, for the rare code that must manage a registration itself.

Signature

function useDocumentClassContext(): { store: DocumentElementStore } | null

// The store's shape (the type is not exported):
interface DocumentElementStore {
  register(id: string, descriptor: DocumentElementDescriptor): void;
  unregister(id: string): void;
  subscribe(listener: () => void): () => void;
  getSnapshot(): ReadonlyMap<string, DocumentElementDescriptor>;
  getServerSnapshot(): ReadonlyMap<string, DocumentElementDescriptor>;
}

Try it live

The store behind useDocumentClass(), reached directly: register and unregister a descriptor by an id you choose.Try this: register, then check the body element in the browser’s element inspector: the class is on it.
Storefront canvas · ar · RTL
Runs in the browser…
Controls
What a theme writes
import { useEffect } from 'react';
import { useDocumentClassContext } from '@salla.sa/twilight-theme-engine/providers';

// Only for code that cannot call useDocumentClass(), such as an integration
// that decides when to add and remove the attributes itself.
export function useManualBodyClass(active: boolean) {
  const ctx = useDocumentClassContext();
  useEffect(() => {
    if (!ctx || !active) return;
    ctx.store.register('my-integration', { body: { class: 'playground-manual' } });
    return () => ctx.store.unregister('my-integration');
  }, [ctx, active]);
}

Example

app/hooks/useManualBodyClass.ts
import { useEffect } from 'react';
import { useDocumentClassContext } from '@salla.sa/twilight-theme-engine/providers';

export function useManualBodyClass(className: string, active: boolean) {
  const ctx = useDocumentClassContext();
  useEffect(() => {
    if (!ctx || !active) return;
    ctx.store.register('my-integration', { body: { class: className } });
    return () => ctx.store.unregister('my-integration');
  }, [ctx, className, active]);
}

How it behaves

  • register stores or replaces the descriptor for an id and notifies subscribers; unregister notifies only when the id existed. Each change creates a new snapshot, which triggers the DOM sync.

  • DocumentElementDescriptor ({ body?: attrs; html?: attrs }) is public from @salla.sa/twilight-theme-engine/utils.

Gotchas

  • Nothing unregisters for you. Pair every register with an unregister in the same effect cleanup, or the attributes stay on <body> for the rest of the visit.

  • Ids are shared with useDocumentClass() (which uses React useId() values). Registering an id that already exists silently replaces that registration.

Related

Source and docs