3U

Theme Configuration

Configure your theme with defineTheme.

defineTheme

The theme config file:

threeu.config.ts — Theme
TypeScript
import { createTheme } from "threeu-sdk/theme";
import HomePage from "./pages/Home";
import ProductPage from "./pages/Product";

export default createTheme({
  name: "Modern Luxury",
  slug: "modern-luxury",
  visibility: "public",
  pages: { home: HomePage, product: ProductPage }
});

Brand Identity: Logo, Palette & Banners

Merchants set their identity once in the ThreeU dashboard: a logo, up to six banner images (hero/slider art, in display order) and a 60/30/10 palette (primary 60% dominant, secondary 30% surfaces, accent 10% calls-to-action) auto-extracted from those images and editable. The storefront config exposes it as config.brand (logo_url, banners[], primary_color, secondary_color, accent_color) and the SDK turns it into the provider's brand object:

Build brand info from getConfig()
TSX
import { ThreeuStorefront } from "threeu-sdk/storefront";
import { ThemeProvider, brandInfoFromConfig } from "threeu-sdk/theme";

const storefront = new ThreeuStorefront({ brand: "my-store", publicToken: PUBLIC_KEY });
const config = await storefront.getConfig();

<ThemeProvider brand={brandInfoFromConfig(config, { locale: "ar" })} storefront={storefront}>
  <App />
</ThemeProvider>

Using Banners & Colours in Pages

Read the identity with useBrand() (name, logo, banners, colors, socials, support) or the focused useBanners(), which returns the owner's banner URLs in order and falls back to fetching the config when the provider was given none. Prefer the owner's banners over bundled hero art, and keep a bundled default for brands that uploaded nothing. In preview mode your demo brand should include banners and colors so reviewers see the real behaviour.

Hero from owner banners + palette
TSX
import { useBrand, useBanners, TImage } from "threeu-sdk/theme";

export function Hero() {
  const brand = useBrand();
  const banners = useBanners();           // string[] — owner order, [] when none
  const hero = banners[0];

  return (
    <section style={{ background: "var(--brand-secondary, #f5f5f5)" }}>
      {hero
        ? <img src={hero} alt={brand?.name ?? ""} />
        : <TImage name="home.hero.image" src="/hero-default.jpg" alt="Hero" />}
      <button style={{ background: "var(--brand-accent, #111)", color: "var(--brand-accent-foreground, #fff)" }}>
        Shop now
      </button>
    </section>
  );
}

Palette CSS Variables

When brand.colors is present the provider writes CSS custom properties on <html> (and removes them on unmount), so plain CSS and Tailwind arbitrary values can follow the merchant's palette with no JavaScript:

VariableValue
--brand-primary, --brand-secondary, --brand-accentThe colour as set by the owner (only roles they set)
--brand-<role>-foreground#000000 or #ffffff, whichever contrasts better
--brand-<role>-50--brand-<role>-950Lightness ladder (50 near white, 500 = base, 950 near black); hex colours only

Always give a fallback (var(--brand-primary, #123456)) — a brand that never set a role keeps your theme's colour. brandCssVars(colors) returns the same map for SSR or inline styles, and applyBrandCssVars(colors, element) targets a specific element. Inside the hosted ThreeU storefront the same variables are provided by the host, so merged themes behave identically.