Theming Demo
A working demo of the theming described in my writeup of the okLCH color system. While that design system doesn't use Tailwind, I've applied the same thinking to this site, so we end up with a pretty close approximation.
You can play around below. The demo is scoped to its container, so it won't affect the rest of the page, but you can always change the whole site's theme in the header if you land on something you like.
<Theme/>How it works
Colors are controlled by data-hue and data-neutral attributes on the <Theme> component, each of which assigns a given color ramp to the alias variables that feed into the theme. These will cascade down from any ancestor, so you can scope overrides to a section of the page.
colors.css: raw okLCH colorshues.css: alias scales for hue and neutral:root→[data-theme]→[data-hue]→[data-neutral]
Colors
Raw oklch palettes are registered with Tailwind in colors.css, making them available as both CSS variables and utility classes (bg-ruby-500, text-sand-200, etc.).
Two alias scales — --hue-* and --neutral-* — act as indirection layers. By default they point to the sand palette, but setting data-hue or data-neutral on any ancestor swaps the entire scale.
File structure
Semantic tokens
Semantic tokens like --primary, --background, and --ring are declared on :root, [data-theme] and reference these aliases. Because [data-theme] is in the selector, the tokens re-evaluate whenever hue or neutral variables are overridden on a descendant.
Radius
Again, constraining myself to shadcn here. No real difference except I made the base radius = 10 for easier math, and I wanted to play with odd-numbered radii.
So you have the --radius base value with these odd multipliers. Instances of <Theme> will inject a new --radius CSS variable, so updated values cascade down.
Components use these via Tailwind utilities like rounded-md, so adjusting the base value rescales every corner radius in the themed scope proportionally.