Theming
Define application-wide theme presets, provider scoping, dynamic theme switching, and portal styling.
Moraine allows you to establish component defaults across your application or within specific subtrees using defineTheme() and MoraineProvider. For colors, fonts, shadows, and sizing tokens, configure UnoCSS themes or write CSS variables. defineTheme() changes component recipes and default variants.
Defining a Theme with defineTheme#
Use defineTheme() from moraine/theme to create a reusable theme configuration:
Extending Themes#
Pass an existing theme to extends to build specialized themes (such as high-contrast or compact modes):
Scoping with MoraineProvider#
Wrap your application root or any subtree in MoraineProvider to activate your theme:
Provider Nesting Behavior#
theme prop |
Behavior |
|---|---|
Omitted or undefined |
Inherits the parent Provider’s theme. At root, uses built-in recipe defaults. |
defineTheme(...) |
Applies specified theme overrides on top of built-in component recipes. |
theme={null} |
Clears inherited theme overrides, resetting the subtree to Moraine defaults. |
Dynamic Theme Switching#
Because Moraine is built natively for SolidJS fine-grained reactivity, changing the theme prop updates classes instantly without unmounting DOM nodes:
Interactive elements keep their focus, text selection, and native element references when themes switch.
State Selectors in Themes#
Variants define stable design dimensions (size, variant, color). Transient state (such as disabled, active, or loading) should use attribute selectors in the base configuration:
Portals & CSS Variables#
Overlay components (Dialog.Content, Popover.Content, Tooltip.Content) render into a Portal attached to document.body by default.
Because portaled nodes are physically rendered outside their parent container in the DOM tree, CSS custom properties declared on local container elements do not cascade into portaled overlays.
To pass custom variables or classes to portaled overlays, pass them directly to the overlay’s root or content slots: