Theming
Two themes in one stylesheet, design tokens exposed as CSS variables, and react-bootstrap-style runtime color control through the provider.
Light & dark
The whole system hangs off one attribute: <html data-theme="dark">. The provider sets it for you and remembers the choice in localStorage under mcl-theme. Use the built-in toggle or the hook:
import { ThemeToggle, ThemeMenu, useTheme } from "marclayui";
// Drop-in pill button:
<ThemeToggle />
// Navbar menu with mode, style preset and color swatches:
<ThemeMenu />
// Or build your own from the hook:
const { mode, preference, setPreference, toggle } = useTheme();
setPreference("dark"); // force dark
setPreference("system"); // follow the OS
toggle(); // flip light/darkStyle presets
A preset is a complete design language: it swaps the light and dark palettes together, plus shape and typography. Claymorphism (default) is warm terracotta clay with squircles and Quicksand; Neumorphism is soft grey-blue extrusion with a violet accent in light mode, a gold accent in dark mode, circles and Poppins/Manrope. Switching a preset also clears any custom runtime colors, so you always see the preset as designed.
import { MarclayProvider, PRESETS } from "marclayui";
// Pick a preset — it swaps the ENTIRE light + dark palette pair:
<MarclayProvider preset="neo">…</MarclayProvider> // neumorphism
<MarclayProvider preset="clay">…</MarclayProvider> // claymorphism (default)
// Or switch at runtime (persisted to localStorage):
const { preset, setPreset } = useTheme();
setPreset("neo");
// Under the hood it's just an attribute — pure CSS theming works too:
// <html data-preset="neo" data-theme="dark">Runtime colors
Give setColors any subset of primary, secondary, accent, success, danger, warning, info, bg, ink, muted. MarclayUI derives everything else — lighter gradient stops, readable ink, clay inner glows, focus rings and even the shadow colors when you change the background.
import { useTheme } from "marclayui";
const { setColors, resetColors } = useTheme();
// One call repaints gradients, clay glows, focus rings
// and readable text colors across every component:
setColors({ primary: "#7c5cff", bg: "#ece7f6" });
resetColors(); // back to the stylesheet defaults// Static colors for the whole app:
<MarclayProvider
defaultMode="dark"
colors={{ primary: "#4a90d9", secondary: "#7fb5c9" }}
>
<App />
</MarclayProvider>Design tokens
Every color, shadow and radius is a CSS custom property, so pure-CSS theming works too — handy for marketing sites or white-label builds:
/* Or theme purely in CSS — override the tokens on :root */
:root {
--mcl-primary: #7c5cff;
--mcl-bg: #ece7f6;
}
[data-theme="dark"] {
--mcl-primary: #9d85ff;
--mcl-bg: #221e2e;
}| Token | Purpose |
|---|---|
--mcl-bg | App background — the surface every shadow is carved from |
--mcl-ink | Primary text color |
--mcl-muted | Secondary text color |
--mcl-primary / -2 / -ink | Brand tone, its lighter gradient stop, and text on it |
--mcl-{tone}-deep | Darkened tone for colored text on the page background (soft badges, stat values) — auto-derived at runtime too |
--mcl-secondary / -2 / -ink | Supporting tone (sage by default) |
--mcl-accent / -2 / -ink | Highlight tone (gold by default) |
--mcl-success | danger | warning | info | Status tones, each with -2 and -ink variants |
--mcl-sd / --mcl-sl | Dark & light shadow colors — the neumorphic light source |
--mcl-out / -sm / -xs | Raised (extruded) shadow stack |
--mcl-in / -sm / -xs | Pressed (inset well) shadow stack |
--mcl-clay-p … -i | Colored inner-light shadows, one per tone |
--mcl-ring | Focus ring color |
--mcl-radius / -sm / -lg | Corner radii (presets ship different shapes) |
--mcl-avatar-radius / --mcl-navbar-radius | Squircle vs circle avatars, pill vs rounded navbar |
--mcl-font / --mcl-mono | Font stacks (clay: Quicksand · neo: Poppins/Manrope) |
Scrollbars | Themed automatically: .mcl-root styles the page scrollbar, .mcl-scroll styles any scrollable container |
Live playground
Everything below is live: swap the style preset and mode, drag the color pickers, squeeze the corner radius and change the typeface — the whole page re-themes in real time. The generated JSX shows exactly what your app needs.
#e0785a#a8b894#d9a854#97897b#ece4da#4a3f35Looking good
Presets swap both palettes; colors, radius and typeface layer on top — instantly.Equivalent JSX
<MarclayProvider />
Provider API
| Prop | Type | Default | Description |
|---|---|---|---|
preset | "clay" | "neo" | "clay" | Style preset; swaps the light+dark palette pair, radii and fonts. Persisted to localStorage. |
setPreset(p) | (p: PresetName) => void | — | Switch preset at runtime; clears custom color overrides so the preset shows cleanly. |
defaultMode | "light" | "dark" | "system" | "system" | Starting mode; persisted to localStorage after the first change. |
colors | ColorOverrides | — | Initial runtime color overrides applied on mount. |
useTheme().mode | "light" | "dark" | — | Resolved mode after 'system' is applied. |
useTheme().preference | "light" | "dark" | "system" | — | What the user picked. |
useTheme().setColors(colors) | (c: ColorOverrides) => void | — | Merge new overrides; derived shades update instantly. |
useTheme().resetColors() | () => void | — | Remove all overrides, back to preset defaults. |