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 |
|---|---|---|
sourceColor | Any hex color | #6750A4 |
scheme | light, dark, system | system |
contrast | standard, medium, high | standard |
variant | tonal-spot, fidelity, content, vibrant, fruit-salad, rainbow | tonal-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.