Skip to main content

createTheme

Creates a type-safe, scoped theme handle. The handle pre-binds a scope identifier and a set of theme variants, providing a Provider component, a reactive accessor, theme switching, and extension — all without exposing raw scope strings.

Signature​

import { createTheme } from '@espcompose/core';

const MyTheme = createTheme(scope, themes, options?);

Parameters​

ParameterTypeRequiredDescription
scopestringYesUnique scope identifier for this theme group
themesRecord<Names, T>YesMap of theme name to theme object
options{ default?: Names }NoWhich theme is active on boot. Defaults to the first entry

Returns​

A ThemeHandle<T, Names, Scope> with the following API:

MemberDescription
handle.ProviderJSX component that registers themes and renders children
handle.select(name)Switch the active theme at runtime (call inside trigger handlers)
handle.use()Access the reactive theme proxy for reading theme values
handle.extend(themes)Create a new handle with additional theme variants
handle.scopeThe raw scope string (used internally by the compiler)

Provider​

The Provider component registers all themes into the global registry and renders its children. Only two props are exposed:

<MyTheme.Provider default="dark">
{/* Themed content */}
</MyTheme.Provider>
PropTypeRequiredDescription
defaultNamesNoWhich theme is active on boot
childrenEspComposeElementNoChild elements

select​

Switch the active theme at runtime. Must be called inside a trigger handler body (onPress, onClick, etc.):

<Button text="Dark" onPress={() => { MyTheme.select('dark'); }} />

The compiler transforms this into a C++ action that sets the scoped theme index signal and flushes the reactive graph — all themed widgets update instantly.

use​

Access the reactive theme proxy. Returns a deeply-nested object whose leaf properties are reactive nodes tied to the current theme:

const theme = MyTheme.use();

// Each leaf is a reactive value that updates when the theme changes
<lvgl-obj style={{ backgroundColor: theme.colors.background }} />

extend​

Add custom theme variants to an existing handle. Returns a new handle for the same scope with the combined set of theme names:

import { UITheme } from '@espcompose/ui';

const MyTheme = UITheme.extend({
ocean: oceanTheme,
forest: forestTheme,
});

// MyTheme now supports 'dark' | 'light' | 'ocean' | 'forest'
<MyTheme.Provider default="ocean">
{/* ... */}
</MyTheme.Provider>

The parent themes are preserved. New themes can override existing names.

Example: custom design system​

import { createTheme, createFontToken } from '@espcompose/core';
import type { FontToken } from '@espcompose/core';

interface MyDesignSystem {
colors: { bg: string; fg: string; accent: string };
font: FontToken;
}

const LcarsTheme = createTheme('lcars', {
standard: {
colors: { bg: '#000000', fg: '#FF9900', accent: '#CC6600' },
font: createFontToken('gfonts://Orbitron', 18),
},
redalert: {
colors: { bg: '#1A0000', fg: '#FF0000', accent: '#CC0000' },
font: createFontToken('gfonts://Orbitron', 18),
},
});

Then use it in your components:

function MyApp() {
const lcars = LcarsTheme.use();

return (
<LcarsTheme.Provider default="standard">
<lvgl-obj style={{ backgroundColor: lcars.colors.bg }}>
<lvgl-label text="Status" style={{ color: lcars.colors.fg }} />
</lvgl-obj>
</LcarsTheme.Provider>
);
}
  • createFontToken — create font asset descriptors for themes
  • Theming — the built-in @espcompose/ui theme system built on createTheme