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

DocumentClassProvider

providerAdvanced

Collects every useDocumentClass() request in its tree and applies the merged classes and attributes to the real body and html elements.

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

In plain words

Several components can want classes on <body> at the same time. DocumentClassProvider keeps the list, merges it, writes the result to the page, and removes what it added when a component goes away.

TwilightProvider already wraps your theme in one. Mount it yourself only in a tree without TwilightProvider, such as a component test.

Signature

function DocumentClassProvider(props: DocumentClassProviderProps): JSX.Element

interface DocumentClassProviderProps {
  children: ReactNode;
}

Example

tests/ProductPage.test.tsx
import { render } from '@testing-library/react';
import { DocumentClassProvider } from '@salla.sa/twilight-theme-engine/providers';
import { ProductPage } from '../app/components/ProductPage';

it('marks the body while the page is mounted', () => {
  const { unmount } = render(
    <DocumentClassProvider>
      <ProductPage />
    </DocumentClassProvider>
  );
  expect(document.body.classList.contains('page-product')).toBe(true);
  unmount();
  expect(document.body.classList.contains('page-product')).toBe(false);
});

How it behaves

  • Its DOM sync is a separate child component that writes in an effect, so server HTML is never touched. It records what it added in a data-de-managed attribute and removes exactly that on the next change, leaving classes set by other code alone.

  • Without any provider, useDocumentClass() writes to the DOM itself.

Gotchas

  • Do not nest a second one inside TwilightProvider. Both sync to the same <body> and share its data-de-managed record, so each removes the other's classes, theme classes such as color-mode-light and rtl included. Registrations below the inner one are also invisible to useDocumentClassOutput() above it.

  • Without a provider, components calling useDocumentClass() overwrite each other: each write replaces the shared managed record, and each unmount clears it, taking the other components' attributes along (src/hooks/useDocumentClass.ts).

Related

Source and docs