Skip to content

Theming ​

Catnip supports theming via CSS variables. Design tokens are exposed as --catnip-* variables that you can override.

Light and Dark Themes ​

Default (light) ​

css
@import "@signicat/catnip-design-tokens/css";

Tokens are applied on :root. Color examples:

  • --catnip-color-content-neutral-strongest
  • --catnip-color-background-neutral-subtlest
  • --catnip-color-brand-500

Typography: responsive --catnip-font-* presets are included in the default CSS bundle (see Typography tokens). Spacing and shadow tokens ship as --catnip-space-* and --catnip-shadow-* (see Spacing tokens and Shadow tokens). Catnip CSS shadow utilities use the same variables.

Component tokens (for example --catnip-button-radius) also ship on :root. Components consume these named variables; themes override them. See Component tokens below.

Dark theme ​

css
@import "@signicat/catnip-design-tokens/css";
@import "@signicat/catnip-design-tokens/css/dark";

Dark semantic color overrides apply when the subtree has data-theme="dark":

html
<html data-theme="dark">
  <!-- Dark semantic colors apply -->
</html>

Or scope to a section:

html
<div data-theme="dark">
  <!-- Only this subtree uses dark semantic overrides -->
</div>

Primitive color variables stay on :root unless you override them yourself.

EndUI (whitelabel) theme ​

Use the EndUI theme for non-Signicat / whitelabel surfaces so primary UI uses the blue brand palette instead of Signicat purple, and main buttons use a squared radius.

EndUI is opt-in: import it from the tokens package (it is not bundled into @signicat/catnip-css). Both files use data-theme="endui". Pick the file for where you set that attribute.

On <html>, import css/endui. That file remaps color.brand.* to the blue scale, sets --catnip-color-accent-300 to Steel 200 (Mint 300 by default), and sets --catnip-button-radius to the squared scale step (radius.s). --catnip-graphic-accent references --catnip-color-accent-300, so illustration accents follow that remap. Semantic aliases such as --catnip-color-content-primary-strong already live on :root, which is the same element, so they recompute against the blue brand.

css
@import "@signicat/catnip-design-tokens/css";
@import "@signicat/catnip-design-tokens/css/endui";
html
<html data-theme="endui">
  <!-- Blue brand + squared main buttons -->
</html>

On a wrapper, import css/endui-scoped. A custom property inherits its computed value. Remapping --catnip-color-brand-* on a child leaves primary content, background, border, and the focus ring on the color already resolved on :root. The scoped file is the css/endui rule plus those dependent variables, repeated with the same var() expressions as :root, so the subtree recomputes them. That includes --catnip-graphic-primary, --catnip-logo-background, and --catnip-shadow-focus-default.

css
@import "@signicat/catnip-design-tokens/css";
@import "@signicat/catnip-design-tokens/css/endui-scoped";
html
<div data-theme="endui">
  <!-- This subtree uses the blue brand, including semantic primary tokens -->
</div>

data-theme can be only one value at a time, so EndUI and dark do not combine in this release. Combining brand + dark is a follow-up.

CDN ​

If you already load css/latest/styles.css, default and dark token rules are included — set data-theme="dark" as above. For EndUI, or when loading tokens without the full CSS package:

html
<link rel="stylesheet" href="https://static.signicat.com/catnip/design-tokens/latest/css/default.css" />
<link rel="stylesheet" href="https://static.signicat.com/catnip/design-tokens/latest/css/dark.css" />
<link rel="stylesheet" href="https://static.signicat.com/catnip/design-tokens/latest/css/endui.css" />
<!-- Subtree EndUI: endui-scoped.css instead of endui.css -->

Then apply dark or EndUI with data-theme="dark" or data-theme="endui" as above. For EndUI on a wrapper, load css/endui-scoped.css instead of css/endui.css. For the full CDN setup (CSS utilities, icons, fonts), see Installation — CDN.

Component tokens ​

Component tokens are named for a control (for example --catnip-button-radius) but defined on :root in the design-tokens package — not invented inside each component stylesheet.

Rules:

  1. Defaults always exist on :root (Signicat look).
  2. Themes override the same variables (for example EndUI sets --catnip-button-radius).
  3. Component SCSS only consumes the variable.
  4. Use a leaf name first (button.radius → --catnip-button-radius). Add a suffix only when a second value is needed (button.radius.utility → --catnip-button-radius-utility).

Per-instance overrides still work: set the CSS variable on a host or wrapper; cascade wins over :root.

See also the shipped inventory: Component tokens.

Overriding tokens ​

Redefine CSS variables where you need custom branding:

css
:root {
  --catnip-color-brand-500: #6d28d9;
  --catnip-color-brand-600: #5b21b6;
}

Custom theme ​

Add another data-theme value and set the variables you want to change. Load that stylesheet after default.css.

On <html>, redefining those variables is enough. Aliases declared on :root recompute on that same element:

css
/* my-theme.css — html only */
[data-theme="brand"] {
  --catnip-color-brand-500: #0ea5e9;
  --catnip-color-brand-600: #0284c7;
}
html
<html data-theme="brand"></html>

On a wrapper, repeat every custom property whose value references a variable you override, using the same var() expression as :root. Indirect references count. --catnip-shadow-focus-default references --catnip-color-border-primary-focus, so the focus shadow has to be in the rule whenever that border token changes. When the theme remaps brand, copy the dependent declarations from endui-scoped.css (primary content, background, and border, graphic primary, logo background, and the default focus shadow). The block below shows the shape; a full brand remap needs the whole dependent set:

css
/* my-theme.css — subtree */
[data-theme="brand"] {
  --catnip-color-brand-500: #0ea5e9;
  --catnip-color-brand-600: #0284c7;

  --catnip-color-content-primary-strong: var(--catnip-color-brand-600);
  --catnip-color-content-primary-strong-hover: var(--catnip-color-brand-500);
  --catnip-color-border-primary-focus: var(--catnip-color-brand-500);
  --catnip-shadow-focus-default: 0 0 0 3px var(--catnip-color-border-primary-focus);
}
html
<div data-theme="brand"></div>

Give the selector a specific value, such as [data-theme="brand"]. A bare [data-theme] rule matches dark and EndUI as well and can override their values.

Prefer shipping shared brand themes the same way as EndUI (token JSON + build).

Token reference ​

See Design tokens for what ships today and Color tokens for the full color list.

Catnip Design System by Signicat