Cotton UI's look is driven by overridable CSS variables. Two colours carry a theme: an accent (your brand) and ink (the neutral behind text, borders and surfaces), alongside radius, surfaces, shadows and the focus ring. Override any with a :root block (and a .dark block for dark mode). Start with the main ones below, or see All Tokens for the full list.
The accent drives primary buttons, active states and focus rings. Cotton UI uses a 3-value accent system:
--color-accent - primary fills (button backgrounds, active states)--color-accent-content - hover states and readable accent text--color-accent-foreground - text and icons on accent fillsA neutral ink accent ships by default. To brand the kit, override the accent tokens with a :root block and a .dark block for dark mode. This goes in the inline <style> from the no-build setup, or your app.css on a custom build, the same three tokens either way:
:root {
--color-accent: var(--color-blue-500);
--color-accent-content: var(--color-blue-600);
--color-accent-foreground: var(--color-white);
}
.dark {
--color-accent: var(--color-blue-400);
--color-accent-content: var(--color-blue-300);
--color-accent-foreground: var(--color-blue-950);
}
Use the Theme Builder to preview and generate the CSS to copy into your app.css.
Where the accent is your brand colour, ink is the neutral the rest of the UI is built from: text, borders, dividers, surfaces and the off-accent state. It's the --color-ink-50…950 scale, defaulting to Tailwind's zinc.
Re-tone the whole UI by pointing those tokens at another scale in a :root block. It's a plain token override, so it works on the no-build <link> path too, and it never touches your own zinc usage:
:root {
--color-ink-50: var(--color-stone-50);
--color-ink-100: var(--color-stone-100);
/* …through the scale… */
--color-ink-900: var(--color-stone-900);
--color-ink-950: var(--color-stone-950);
}
The Theme Builder generates the full block for any tone, including the warm and cool neutrals the kit ships. Together, accent and ink are the two colours every theme turns on.
Add :accent="False" as a property to turn off accent highlights for a component. Its selected and active states (a checked radio, an on switch, a selected card) render in ink instead, no theme changes needed, so they re-tone with your neutral and flip light/dark on their own.
The off-accent fill is the --color-muted token, which defaults to ink (--color-ink-900 / --color-ink-100). Override it for a different neutral, e.g. a softer mid-ink:
:root {
--color-muted: var(--color-ink-600);
}
.dark {
--color-muted: var(--color-ink-400);
}
Two radius tokens control rounding. Form controls and structural surfaces are kept separate so you can, for example, round cards more than inputs:
--radius-control - form controls (inputs, buttons, segments)--radius-box - structural surfaces (cards, dialogs, menus):root {
--radius-control: 0.5rem; /* form controls */
--radius-box: 0.75rem; /* structural surfaces */
}
Surface tokens set the page base and the raised surfaces drawn on top of it. The faint tinted base lets white cards and menus read as elevated:
--color-bg - page base background--color-surface - raised surfaces (cards, dialogs, menus)--color-input-bg - form field fill (transparent in light so fields are border-defined; a faint lift in dark):root {
--color-bg: var(--color-ink-50); /* page base */
--color-surface: #ffffff; /* cards, dialogs, menus */
--color-input-bg: transparent; /* form fields (border-defined) */
}
.dark {
--color-bg: var(--color-ink-900);
--color-surface: var(--color-ink-800);
}
The complete set of themeable tokens and their defaults. Override any of them in a :root block, and set dark-mode values under .dark.
| Token | Default | Dark | Purpose |
|---|---|---|---|
| Neutral (Ink) | |||
--color-ink-50…950 |
Tailwind zinc | - | The neutral scale behind text, borders, dividers and surfaces. Re-tone it to re-skin the UI; defaults to zinc and never touches your own zinc usage. |
--color-muted |
ink-900 | ink-100 | Fill and border for :accent="False" controls; defaults to ink. |
| Accent | |||
--color-accent |
ink-900 | ink-100 | Primary fills: button backgrounds, active states |
--color-accent-content |
ink-700 | ink-300 | Hover states and readable accent text |
--color-accent-foreground |
white | ink-900 | Text and icons on accent fills |
| Surfaces | |||
--color-bg |
ink-50 | ink-900 | Page base background |
--color-surface |
white | ink-800 | Raised surfaces: cards, dialogs, menus |
--color-input-bg |
transparent | +4% white | Form field fill: transparent in light (border-defined), a faint lift in dark |
--color-box-border |
ink-200 | ink-700 | Border on box surfaces: cards, dialogs, menus, popovers. Set transparent for a shadow-only look |
--color-card-border |
= box-border | = box-border | Card border only. Falls back to --color-box-border; override it alone (e.g. transparent) to affect just cards |
| Radius | |||
--radius-control |
0.375rem | Form controls: inputs, buttons, segments | |
--radius-box |
0.5rem | Structural surfaces: cards, dialogs, menus | |
| Shadows | |||
--shadow-input |
0 1px 2px 0 rgb(0 0 0 / 0.05) | Form input elevation (set to none to flatten) | |
--shadow-box |
0 1px 2px 0 rgb(0 0 0 / 0.05) | Card and dialog elevation | |
| Focus ring | |||
--focus-ring-width |
2px | Focus ring thickness | |
--focus-ring-offset |
0px | Gap between the control and the ring | |
--focus-ring-color |
= accent | Focus ring color | |
--focus-ring-offset-color |
white | ink-900 | Color behind the offset gap |
Cotton UI uses Tailwind's built-in zinc for grays, which works with zero configuration. If you prefer a different gray family, remap zinc to another palette:
/* Remap zinc to slate */
@theme {
--color-ink-50: var(--color-slate-50);
--color-ink-100: var(--color-slate-100);
--color-ink-200: var(--color-slate-200);
--color-ink-300: var(--color-slate-300);
--color-ink-400: var(--color-slate-400);
--color-ink-500: var(--color-slate-500);
--color-ink-600: var(--color-slate-600);
--color-ink-700: var(--color-slate-700);
--color-ink-800: var(--color-slate-800);
--color-ink-900: var(--color-slate-900);
--color-ink-950: var(--color-slate-950);
}
Theming approach inspired by Flux UI.