One of the non-negotiable requirements for a reusable component library is that reskinning a site for a new client should never require hunting through component files to change colors. HoTMoL solves this with a single file: src/styles/theme_child.css. Change the values there and the entire site updates automatically, across every component and every page.
The Token System
TailwindCSS v4 introduced a CSS-first configuration model where you define utility classes directly in CSS using @utility and custom properties. HoTMoL uses this to expose a set of semantic tokens that every component references:
:root {
--color-primary: #2563eb;
--color-surface: #ffffff;
--color-surface-alt: #f8fafc;
--color-content: #0f172a;
--color-outline: #e2e8f0;
}
These map to Tailwind utilities like bg-primary, text-content, border-outline, and bg-surface-alt, the only color utilities components are allowed to use. Hardcoded colors like bg-blue-600 or text-gray-900 don’t exist anywhere in the component library.
Why Semantic Tokens Over Raw Utilities
When you write bg-blue-600 in a component, you’ve made a decision that belongs to the client’s brand, not the component. Every time you clone the repo for a new client, you have to hunt for every color reference. With semantic tokens, you make that decision once, in one file, and every component inherits it.
The names matter too. bg-surface-alt says “the alternate background for a section,” so a designer reading the markup knows what it means and where to change it. bg-slate-50 says nothing about intent.
Dark Mode Without Duplication
The token system also handles dark mode without duplicating component markup. A single class on the <html> element, cf-theme-dark, overrides the root tokens:
.cf-theme-dark {
--color-surface: #0f172a;
--color-surface-alt: #1e293b;
--color-content: #f1f5f9;
--color-outline: #334155;
}
Every component flips automatically. No dark: prefixes in templates, no conditional class logic, no duplicate markup. The components never know dark mode exists. They just use tokens.
Adapting for a New Client
When you start a client project, the theming workflow is:
- Open
src/styles/theme_child.css - Set
--color-primaryto the client’s brand color - Adjust surface and content colors if the client has a specific palette
- Done
For most service-business clients, changing --color-primary is the entire customization. The rest of the token defaults (clean white surfaces, near-black content, subtle borders) work for almost any brand without modification.
One Exception: btn-light
There’s one hardcoded exception in the system: btn-light, used for buttons that appear over dark image backgrounds (heroes, full-bleed CTAs). It’s hardcoded to #ffffff text on #111827 background because semantic tokens can’t reliably produce sufficient contrast over an arbitrary hero image. This is a deliberate exception, not an oversight. The rest of the system is clean.
The Bigger Principle
Design tokens are a forcing function for good component architecture. If your components reference tokens instead of raw values, they’re already written correctly for reuse. If they reference raw values, they’re not, and you’ll feel that pain every time you clone the repo. HoTMoL enforces the discipline by rule: border-outline, not border-gray-200. text-content, not text-slate-900. One file controls everything.