Skip to main content

Theming

widgemo-core ships with a built-in default theme and supports three levels of customization — from zero-config presets to full brand control to targeted per-zone overrides.

ApproachBest forScope
1. Built-in presetLight, dark, or OS-aware mode with no setupEntire subtree
2. Custom theme objectBrand palette, spacing, and shared visual rulesEntire subtree
3. Per-zone themeOverridesTargeted header or footer styling without a global providerSingle zone

1. Built-in Presets​

Pass a preset string to WidgemoThemeProvider for instant theming with no additional configuration.

  • theme="light" — default; white surfaces and dark text
  • theme="dark" — dark surfaces and light text
  • theme="auto" — follows the OS preference at render time via window.matchMedia('(prefers-color-scheme: dark)'); does not subscribe to live changes

WidgemoThemeProvider is optional if the default light theme is all you need — <Widgemo> renders with built-in light styles when no provider is present.

Example Widgemo (Default Light)​

Team Directory

Baseline themed Widgemo

Name
Role
Status
AliceEngineeractive
BobDesignerpending
CharlieProductinactive

Example Widgemo (Default Dark)​

Team Directory

Baseline themed Widgemo

Name
Role
Status
AliceEngineeractive
BobDesignerpending
CharlieProductinactive

Example Code​

<WidgemoThemeProvider theme="light">
<Widgemo data={data} config={config} />
</WidgemoThemeProvider>

<WidgemoThemeProvider theme="dark">
<Widgemo data={data} config={config} />
</WidgemoThemeProvider>

{/* Follow OS preference at render time */}
<WidgemoThemeProvider theme="auto">
<Widgemo data={data} config={config} />
</WidgemoThemeProvider>

For branded customization, use a custom theme object (option 2) or per-zone themeOverrides (option 3). For full token lists, see Theme API and CSS Variable Reference.

2. Custom Theme Object​

Use a custom theme object when you want consistent brand tokens applied across all widgets in a subtree. Pass the object to WidgemoThemeProvider — it can wrap your whole app or just one section of the page.

The example below uses an indigo brand palette.

Example Widget​

Team Directory

Branded with a custom theme

Name
Role
Status
AliceEngineeractive
BobDesignerpending
CharlieProductinactive

Example Code​

// Provider theme — applies globally to all Widgemo widgets in the subtree
const theme = {
colors: {
primary: '#6366f1', // drives variant:'primary' action buttons
btnPrimaryHoverBg: '#4f46e5',
tableHeaderBg: '#ede9fe', // lavender tint on table column headers
tableHeaderHoverBg: '#ddd6fe',
},
spacing: {
borderRadius: '8px', // camelCase key → --widgemo-borderRadius
},
zone: {
titleColor: '#3730a3', // applied to zones without themeOverrides
subtitleColor: '#6366f1',
},
};

// Zone-level config — header uses themeOverrides for an explicit dark background
const config = {
zones: {
header: {
title: 'Team Directory',
subtitle: 'Branded with a custom theme',
themeOverrides: {
backgroundColor: '#1e1b4b', // deep indigo — overrides provider zone tokens
titleColor: '#e0e7ff',
subtitleColor: '#a5b4fc',
},
actions: [
{ id: 'invite', label: 'Invite', icon: 'plus', placement: 'pinned', variant: 'primary' },
],
},
content: {
mode: 'table',
actions: [
{ id: 'view', label: 'View', icon: 'view', placement: 'pinned' },
],
item: {
fields: [
{ key: 'name', label: 'Name' },
{ key: 'role', label: 'Role' },
{ key: 'status', label: 'Status', renderAs: 'badge' },
],
layout: { type: 'auto' },
},
},
},
};

<WidgemoThemeProvider theme={theme}>
<Widgemo data={data} config={config} />
</WidgemoThemeProvider>

colors.primary drives variant: 'primary' action buttons (background + white text). Ghost and DevMode Inspector buttons use separate tokens and are unaffected. themeOverrides on a zone config always wins over provider zone tokens — use it whenever you need a reliable zone-level background override.

3. Per-Zone Theme Overrides​

Use themeOverrides when only part of a Widgemo needs special styling — the header or footer — and you don't want to introduce a full global theme object.

Example Widgemo

Team Directory

Per-zone overrides applied

Name
Role
Status
AliceEngineeractive
BobDesignerpending
CharlieProductinactive

Last synced just now

The example uses a dark navy header (#0f172a) with a blue 2px accent bottom border — explicitly dark colors are intentional and read correctly in both light and dark modes. The footer's background is not overridden, so it adapts to whichever mode is active. Zone and item actions are wired via interactions.onEvent — click Export in the header, View on any row, or View All in the footer.

Example Code​

const config = {
interactions: {
onEvent: (ctx) => { /* route ctx.interactionId to your handler */ },
},
zones: {
header: {
title: 'Team Directory',
actions: [
{ id: 'export', label: 'Export', icon: 'export', placement: 'pinned', variant: 'primary' },
],
themeOverrides: {
backgroundColor: '#0f172a', // explicit dark — works in both light and dark modes
titleColor: '#f1f5f9',
subtitleColor: '#94a3b8',
// variant:'primary' on the action handles button readability — no color hack needed
borderColor: '#3b82f6',
borderWidth: '0 0 2px 0', // bottom border only
borderStyle: 'solid',
},
},
content: {
mode: 'table',
actions: [
{ id: 'view', label: 'View', icon: 'view', placement: 'pinned' },
],
item: { /* ... */ },
},
footer: {
subtitle: 'Last synced just now',
actions: [
{ id: 'view-all', label: 'View All', icon: 'external-link', placement: 'pinned' },
],
themeOverrides: {
// no backgroundColor — adapts to the active light/dark mode
subtitleColor: '#94a3b8',
},
},
},
};

Runtime Theme Precedence​

When multiple theming sources apply to the same element, higher-priority values win:

  1. Per-zone themeOverrides in config — inline styles applied directly to that zone; always wins
  2. Provider theme.zone — baseline zone styles shared across all zones in the subtree
  3. Provider theme.colors / theme.spacing — CSS variable tokens injected into the subtree
  4. Built-in stylesheet defaults — lowest priority; the fallback when nothing else is set

Use WidgemoThemeProvider for global consistency and themeOverrides for zone-level exceptions.

Accessing Theme in Custom Components​

If you're authoring a custom extension renderer, you can read the active provider theme using useWidgemoTheme():

function MyModeHeader() {
const theme = useWidgemoTheme();
return <header style={{ background: theme.zone?.backgroundColor }} />;
}

Without a provider, useWidgemoTheme() returns {}.

References​