Kesko Themes ships per-brand CSS overrides for our design tokens. Each theme swaps the themeable subset of design tokens while leaving the rest of the token set unchanged.
Installation #
To install Kesko Themes as a dependency in your project, run:
npm install @kesko/themespnpm add @kesko/themesyarn add @kesko/themesbun add @kesko/themesUsage #
A theme file is an override stylesheet. Import the CSS Framework first, then apply a brand theme on top:
@import "@kesko/css/dist/kesko.min.css";
@import "@kesko/themes/dist/kespro.css";Or from HTML:
<link rel="stylesheet" href="@kesko/css/dist/kesko.min.css" />
<link rel="stylesheet" href="@kesko/themes/dist/kespro.css" />Dark mode #
For dark mode, load the dark variant instead of the light one:
@import "@kesko/css/dist/kesko.min.css";
@import "@kesko/themes/dist/kespro-dark.css";Each file also sets color-scheme: light or color-scheme: dark, so native browser UI such as scrollbars and form controls adapts automatically.
Switching between modes #
When both modes need to be available at runtime, scope each file to prefers-color-scheme or to an attribute you control yourself:
<link rel="stylesheet" href="/css/kespro.css" media="(prefers-color-scheme: light)" />
<link rel="stylesheet" href="/css/kespro-dark.css" media="(prefers-color-scheme: dark)" />For explicit user control, toggle a data-theme-mode attribute on the root element and load the matching file in CSS:
@import "@kesko/themes/dist/kespro.css" (prefers-color-scheme: light);
@import "@kesko/themes/dist/kespro-dark.css" (prefers-color-scheme: dark);Themeable tokens #
By default, each brand overrides a subset of @kesko/tokens listed below. All other tokens such as motion, shadows, layers, opacity, and the full primitive palette inherit from @kesko/tokens unchanged.
| Category | Tokens |
|---|---|
| Accent colors | --k-color-accent, --k-color-accent-secondary |
| Text on surface | --k-color-text-on-accent, --k-color-text-on-secondary, --k-color-text-on-disabled, --k-color-text-on-decorative |
| Inline text | --k-color-text-link |
| Borders | --k-color-border-divider |
| Fills | --k-color-fill-decorative, --k-color-fill-secondary |
| Backgrounds | --k-color-bg-highlight, --k-color-bg-disabled, --k-color-bg-hover, --k-color-bg-inverted, --k-color-bg-subtle, --k-color-bg-muted |
| Radius | --k-radius-button, --k-radius-input, --k-radius-checkbox, --k-radius-element |
| Spacing | --k-space-button |
Output formats #
{brand}.css #
Light mode overrides. Contains only the themeable tokens as resolved values under :root.
:root {
color-scheme: light;
--k-color-accent: #cb4700;
--k-color-accent-secondary: #552c87;
--k-radius-button: 0.25rem;
/* ... */
}{brand}-dark.css #
Complete dark mode. Contains all semantic color tokens (backgrounds, text, borders, fills, status, overlay) from the base dark theme, plus brand-specific dark overrides.
:root {
color-scheme: dark;
--k-color-bg: #1b1b1b;
--k-color-text: #ededed;
--k-color-accent: #f86800;
/* ... */
}{brand}.json #
JSON describing both light and dark resolved values, including the original alias reference and an auto flag that indicates whether each dark value was auto-generated or manually overridden:
{
"meta": { "name": "kespro" },
"light": {
"--k-color-accent": { "value": "#cb4700", "ref": "{color.orange.800}" }
},
"dark": {
"--k-color-accent": { "value": "#f86800", "ref": "{color.orange.700}", "auto": true }
}
}Dark mode generation #
Dark mode is produced from two layers, in order:
- Base dark theme:
@kesko/tokensships adarkmode config that maps every semantic color token to its dark equivalent. It uses the dedicatedneutral-darkpalette for neutrals and the palette symmetry rule for saturated colors. - Brand dark overrides: each brand's theme may include a
dark:section for tokens where the auto-mirrored value needs adjustment.
# Brand theme
# Light mode overrides
color:
accent:
base:
value: "{color.orange.800}"
# Optional: manual dark mode overrides
dark:
color:
accent:
base:
value: "{color.orange.700}"When a brand token has no explicit dark: entry, the symmetry rule produces the mirrored value automatically and the JSON output marks it with "auto": true.