Theme contract
Signature of the theme() mixin in
src/theme/_create.scss, the tokens the framework consumes,
and what happens when a theme omits a token.
Mixin signature
@mixin theme(
$name,
$variables: (),
$combinations: (),
$is-default: false,
$root-when: null,
$modifier-class: null,
);
Parameters
| Parameter | Type | Default | Effect |
|---|---|---|---|
$name | string | required | Reserved for diagnostics. No effect on emitted CSS. |
$variables | map | () | Map of scalar token short-name → value. The factory adds the --kc- prefix. Keys absent from the map are not emitted; consumers fall back to each component's hardcoded SCSS-time default. |
$combinations | map | () | Map of combination label → (bg, fg) tuple. Each tuple expands to --kc-<label>-bg and --kc-<label>-fg. Use map.merge(variables.$color-combinations, …) to override individual entries while keeping the rest. |
$is-default | bool | false | When true, emits the variables on :root unconditionally. |
$root-when | string | null | Wraps an emit block in a media query. Pass strings like 'prefers-color-scheme: dark'. |
$modifier-class | selector | null | When set, emits a second block under that class: typically .theme-dark. |
$is-default, $root-when, and $modifier-class are independent. A
theme may set any subset. Setting none emits nothing: useful for
parameterising a base map shared across multiple themes.
Tokens consumed by the framework
The factory does not validate the maps you pass — both $variables
and $combinations are optional and may be partial. A token absent from
the emitted CSS falls through to the component's SCSS-time fallback
(var(--kc-bg, #ffffff) etc.). The framework consumes:
Scalar tokens ($variables)
bg,fg: page background and foreground (base/global).link,link-hover: anchor colours (typography/link,element/button.is-link).focus-ring::focus-visibleoutline colour (Button, Link). Aim for ≥3:1 against every adjacent surface (WCAG 2.4.13 AAA).border-radius: surface rounding (Card, Modal, etc.).card-bg,card-fg: Card surface colours (module/card).
Components consume additional tokens that aren't mandatory: e.g.
module/modal reads --kc-modal-backdrop (the bundled dark theme
ships it; default and high-contrast don't).
Combinations ($combinations)
One (bg, fg) tuple per label in $color-combinations: by default
default, primary, warning, danger, success. Each tuple expands
to --kc-<label>-bg and --kc-<label>-fg, consumed by Button and Card
variants.
Fallback semantics
A token omitted from the emitted block resolves to the SCSS-compile-time
fallback baked into each component plugin. Those fallbacks reflect the
default palette, not the theme that omitted the token. A partial
dark theme that drops bg therefore renders against a white page, not
the theme's intended dark surface — usually not what you want.
There is no compile-time validation: a typo (bg-color: #000
instead of bg: #000) produces a silently broken theme rather than an
error. Themes are expected to ship a complete map for the surfaces they
care about.
Minimal theme
// src/theme/my-theme.scss
@use '../variables';
@use 'create';
$variables: (
bg: #fff,
fg: #27282b,
link: #1a6347,
link-hover: #525a22,
border-radius: variables.$global-border-radius,
card-bg: #fff,
card-fg: #27282b,
focus-ring: #1a6347,
);
$combinations: (
default: (#fff, #27282b),
primary: (#2a8d69, #fff),
warning: (#7a4f10, #fff),
danger: (#8c351a, #fff),
success: (#525a22, #fff),
);
@include create.theme(
$name: 'my-theme',
$variables: $variables,
$combinations: $combinations,
$is-default: true,
);
Output shape
For each enabled emit block, the factory writes the scalar variables followed by two custom properties per combination:
/* When $is-default is true */
:root {
--kc-bg: #fff;
--kc-fg: #27282b;
/* … remaining scalars … */
--kc-default-bg: #fff;
--kc-default-fg: #27282b;
--kc-primary-bg: #2a8d69;
--kc-primary-fg: #fff;
/* … one bg/fg pair per combination … */
}
See also: --kc-* tokens,
how-to: author a custom theme.