Themes

Themes are named style sets that you define once and reference across your entire .kern file with the $ prefix.

Defining a theme

A theme node has a name and a style block with the same shorthand syntax as inline styles:

theme primary {bg:#f97316,c:#fff,br:8,p:12}
theme danger {bg:#ef4444,c:#fff,br:8,p:12}
theme muted {bg:#27272a,c:#a1a1aa,br:8,p:8}

The name can be a bare identifier after the theme keyword — no name= required:

theme primary {bg:#f97316}       ← bare word becomes name=primary
theme name=primary {bg:#f97316}  ← equivalent explicit form

Referencing themes: $ref

Apply a theme to any node with the $ prefix followed by the theme name:

theme primary {bg:#f97316,c:#fff,br:8,p:12}

button text="Save" $primary
button text="Cancel" $primary
card $muted
  text value="Hint text"

The $ token is parsed as a themeRef — the parser collects all $refs on a line and attaches them to the node.

Style merging

Theme styles merge with inline styles. Inline styles override theme styles when both specify the same property:

theme primary {bg:#f97316,c:#fff,br:8,p:12}

button text="Save" $primary {bg:#ea580c}
// Result: bg=#ea580c (overridden), c=#fff, br=8, p=12 (from theme)

The compiler first applies all theme ref styles in order, then overlays inline styles. This means:

  • Theme styles provide the base
  • Inline styles override specific properties
  • Multiple $refs merge left to right

Multiple theme references

A node can reference multiple themes. They merge left to right:

theme card-base {bg:#18181b,br:12,p:24}
theme card-elevated {"box-shadow":"0 4px 12px rgba(0,0,0,0.3)"}

card $card-base $card-elevated
  text value="Elevated card with both style sets"

How themes compile

Theme nodes are collected in a pre-pass before rendering. They don't produce any output themselves — they only provide styles for $ref resolution.

React (web target)

Theme styles expand through the shorthand system and become inline React style objects:

// KERN source
theme primary {bg:#f97316,c:#fff,br:8}
button text="Save" $primary

// Compiled React output
<button style={{
  backgroundColor: '#f97316',
  color: '#fff',
  borderRadius: 8
}}>Save</button>

Tailwind target

In the Tailwind target, theme styles are converted to utility classes where possible:

// KERN source
theme primary {bg:#f97316,c:#fff,br:8}
button text="Save" $primary

// Compiled Tailwind output
<button className="bg-[#f97316] text-white rounded-lg">Save</button>

Scope

Themes are scoped to the file they are defined in. The compiler collects theme definitions by walking the IR tree before rendering any nodes. A theme defined at any level of the tree is available to all nodes in the same file.

Theme + pseudo-selectors

Themes support the same pseudo-selector syntax as inline styles:

theme interactive {bg:#f97316,c:#fff,:hover:bg:#ea580c,:press:bg:#c2410c}

button text="Click me" $interactive

The pseudo-styles from the theme are merged into the node's pseudoStyles map and compiled to framework-specific hover/active handling.

CSS escape hatch in themes

Themes support the same quoted-key escape hatch as inline styles for any CSS property not in the 30-shorthand map:

theme glass {
  bg:rgba(255,255,255,0.1),
  "backdrop-filter":"blur(8px)",
  "border":"1px solid rgba(255,255,255,0.2)",
  br:16
}

card $glass
  text value="Frosted glass effect"