Files
skills/docs/ui/react/react-auth-whitelabel/src/context/branding-context.md
2026-05-29 08:20:56 +01:00

3.0 KiB

<BrandingProvider> and tenant branding hooks

Purpose

branding-context.tsx ships the <BrandingProvider> React context provider together with the hooks useBranding, useTenantBranding, and useLogo. The provider's job is to resolve a TenantBranding payload (either static via prop or fetched from a configurable endpoint) and to project that payload onto two surfaces: (1) the @suaveplan/react-ui runtime theme-token layer for every --brand-* CSS custom property, and (2) the non-CSS DOM chrome — document.title, <link rel="icon">, and the tenant custom-CSS <style> injection. The CSS path goes through useThemeMutator().setExtensionTokens(...) so per-tenant tokens stack on top of the active chassis theme exactly like any other mutator layer, with automatic cleanup on unmount.

Features

  • Static branding via prop OR endpoint fetch via brandingEndpoint (+ optional /tenantId segment).
  • Injectable fetch: FetchLike for testability.
  • Zod validation (TenantBrandingSchema.safeParse) on every fetched payload — Zod failures surface as BRANDING_INVALID_PAYLOAD.
  • Network failures (transport throw or non-ok response) surface as BRANDING_FETCH_FAILED.
  • --brand-primary, --brand-secondary, --brand-accent, --brand-font written via setExtensionTokens — cleanup is automatic on unmount.
  • document.title, favicon <link>, and tenant <style> injection are direct DOM writes (not CSS variables; no conflict with the mutator).

Usage: Basic

import { ThemeProvider, lightTheme } from "@suaveplan/react-ui/theme";
import { BrandingProvider } from "@suaveplan/react-auth-whitelabel";

<ThemeProvider themes={[lightTheme]} defaultTheme="light">
    <BrandingProvider staticBranding={tenantBranding}>
        <App />
    </BrandingProvider>
</ThemeProvider>

Usage: Advanced

<BrandingProvider
    brandingEndpoint="/api/branding"
    tenantId={tenantSlug}
    fetch={customFetch}
>
    <App />
</BrandingProvider>
const branding = useTenantBranding();
const lightLogo = useLogo(false);
const darkLogo = useLogo(true);

API Reference

  • BrandingProvider(props) — props include brandingEndpoint?, tenantId?, staticBranding?, fetch?, children.
  • useBranding() — returns { branding, isLoading, error, refresh }.
  • useTenantBranding() — returns the current TenantBranding.
  • useLogo(preferDark?) — returns the most-appropriate logo URL or undefined.

Implementation Notes

The mutator effect runs on every branding change AND on every mutator identity change. The mutator handle is stable across re-renders (it's useMemo-wrapped inside @suaveplan/react-ui), so the effect only re-fires when the branding payload actually changes. The cleanup contract for --brand-* is delegated to useThemeMutator — when the provider unmounts, the runtime invokes the mutator's clear() automatically, removing every --brand-* declaration from document.documentElement.style.