Theming

Generate an M3 color scheme from one source color, in light or dark, at three contrast levels.

Dynamic color

By default, App generates every color role from themeState with Material's color utilities, and writes them as CSS variables. Change the state and the whole app recolors:

<script lang="ts">
  import { themeState } from '@noxlovette/material';
</script>

<button onclick={() => (themeState.sourceColor = '#006a60')}>Teal</button>
<button onclick={() => (themeState.scheme = 'dark')}>Dark</button>
Field Values Default
sourceColorAny hex color#6750A4
schemelight, dark, systemsystem
contraststandard, medium, highstandard
varianttonal-spot, fidelity, content, vibrant, fruit-salad, rainbowtonal-spot

The state is saved to localStorage and restored on load. Before first paint, an inline script applies the saved scheme, so a dark-mode user never sees a light flash.

Theme settings

ThemeSwitcher is a ready-made floating action button (FAB) that opens ThemeSettings: source color, scheme, contrast and variant. Drop it inside App, or render ThemeSettings in your own settings page.

<App>
  {@render children()}
  <ThemeSwitcher />
</App>

Color from an image

extractColorFromImage(file) returns the image's dominant color, ready to use as the source color:

import { extractColorFromImage, themeState } from '@noxlovette/material';

const color = await extractColorFromImage(file);
if (color) themeState.sourceColor = color;

Static themes

To ship fixed colors instead, pass dynamicTheme={false} to App and rely on the imported theme files. App still keeps the dark class in sync with the user's scheme, so the dark theme file applies.

Static contrast is chosen by themeState.contrast: App sets data-theme on <html> to light, light-mc, light-hc, dark, dark-mc or dark-hc. Import @noxlovette/material/theme/dark-hc (and the others you need) to supply those colors; the standard themes need no attribute.

Using color roles

Color roles are Tailwind colors named after the M3 token: bg-md-sys-color-primary-container, text-md-sys-color-on-primary-container. Always pair a container with its on-* role; the pair keeps AA contrast in every scheme and contrast level.