Skip to main content
Posts

Theming Demo

A working demo of the theming described in my writeup of the okLCH color system I made. 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.

I guess Tailwind now converts oklch to okLab when compiling (as of v4.2 or so?), so inspected values may not match what's in the code. Shouldn't really matter though, since the two convert cleanly, but just FYI.
<Theme>
Settings
Colors
sand
sand
px
Preview
NeutralInfoSuccessWarningError
NeutralInfoSuccessWarningError
NeutralInfoSuccessWarningError
Neutral
Secondary
Info
Success
Warning
Error

How it works*

* just on this site, not the actual project

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    │
            ╚────────┬─────────╝
                     │
      ╭──────────────┴──────────────╮
      │                             │
      ▼                             ▼
╔────────────────╗          ╔───────────────╗
│    hues.css    ├─ ─ ─ ─ ─►│  globals.css  │
╚────────────────╝          ╚──────┬────────╝
        │                          │
        │                       Tokens
        │                          │
        ╰──╮        ╭──────────────╯
           │        │ 
           │        ▼
  ╔╌╌╌╌╌╌╌╌│╌╌╌╌╌<Theme>╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╗
  ╎     ╭──▼───────╮ ╭──────────────╮     ╎
  ╠─────│ data-hue ├─┤ data-neutral │─────╣
  ╎  ╭──╯╌╌╌╌╌╌╌╌╌╌╰─╯╌╌╌╌╌╌╌╌╌╌╌╌╌╌╰──╮  ╎
  ╎  │         {children}              │  ╎
  ╎  ╰─────────────────────────────────╯  ╎
  ╚╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╝

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

hues.css

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.

(Despite my reservations, I'm using shadcn tokens on this site to see what the hype's about / how my colors work with them; this isn't what's used in the actual project.)

globals.css

Radius

Just for fun, I made the base radius = 10 for easier math, and I also 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 and re-scale instances.

I also capped the values with some eyeballing to avoid absurdly large radii; I'd prefer to use a more precise approach, but this is a quick and dirty solution.

globals.css

PS — If you're wondering what the --ellipse-factoris for, it has nothing to do with theming. I made a utility class for squircle corners, and that'll offset the radius variable to get the desired effect.

globals.css