Skip to content

Import System

Sassy supports splitting a theme across multiple files using the config.import array. Imported files contribute palette definitions, variables, colours, token colours, and semantic token colours to the final theme.

config:
name: "My Theme"
type: dark
import:
- ./shared/variables.yaml
- ./shared/colors.yaml
- ./shared/tokenColors.yaml

Paths are relative to the importing file.

Content TypeMerge Behaviour
paletteDeep merge; later values override earlier ones
varsDeep merge; later values override earlier ones
colorsDeep merge; later values override earlier ones
semanticTokenColorsDeep merge; later values override earlier ones
configDeep merge; later values override earlier ones
tokenColorsAppend-only concatenation (order preserved)
  1. Imports are processed in array order, left to right.
  2. Each successive import is deep-merged (or appended for tokenColors) onto the accumulated result.
  3. The main file’s own palette, vars, colors, semanticTokenColors, and tokenColors are applied last, giving the main file final override authority.
import[0] → import[1] → ... → import[n] → main file

This same order determines source location resolution: when a key is defined in multiple files, tools like resolve report the location from the last file in the chain that defines it — the effective definition. For example, if an import defines palette.pink and the main file overrides it, the reported location points to the main file.

VS Code evaluates tokenColors rules using first-match semantics. The order of rules matters:

  • Imported tokenColors appear first in the output.
  • The main file’s tokenColors are appended after all imports.

This means imports provide the base/specific rules while the main file can add fallback rules that only apply if no import already matched.

Variable substitution is supported in import paths. Variables from config are available:

config:
name: "Midnight Ocean"
type: dark
import:
- ./import/tokenColors-$(type).yaml

Here $(type) resolves to dark, producing the path ./import/tokenColors-dark.yaml.

When redefining a palette key that already exists from a prior import, the séance operator (^) substitutes the accumulated prior value of that key inline.

FormSyntax
Bare^
Parenthesised^()
Braced^{}

All three forms are equivalent. Use whichever reads cleanly in context.

Given an imported palette that defines black: oklch(.145 0 0), a later file can derive from it:

palette:
black: darken(^, 5)

The ^ is replaced with the accumulated prior value of black before evaluation. The operator is resolved at compile time before the palette is evaluated. The prior value is captured as a synthetic palette token, which means the full derivation chain is visible in resolve output.

Chaining: If multiple import layers each redefine the same key with ^, each step captures the accumulated value to that point in the import sequence. Each layer sees the result of the previous one.

Constraints:

  • Only valid in palette definitions.
  • Only fires on leaf (string) values — not on object nodes.
  • Silently passes through if no prior value exists for the key.

In watch mode (--watch), Sassy automatically tracks all imported files. When any imported file changes, the theme is recompiled. No additional configuration is needed.

my-theme/
├── theme.yaml # Main entry: config + theme overrides
├── shared/
│ ├── palette.yaml # Colour palette definitions
│ ├── variables.yaml # Semantic variables
│ ├── colors.yaml # VS Code colour mappings
│ ├── tokenColors.yaml # Syntax highlighting rules
│ └── semanticTokenColors.yaml # Semantic token styling

theme.yaml

config:
name: "My Theme"
type: dark
import:
- ./shared/palette.yaml
- ./shared/variables.yaml
- ./shared/colors.yaml
- ./shared/tokenColors.yaml
- ./shared/semanticTokenColors.yaml
theme:
colors:
# Override specific colours from imports
statusBar.background: $$blue

shared/palette.yaml

palette:
blue: "#61afef"
cyan: "#56b6c2"

shared/variables.yaml

vars:
accent: $$cyan
std:
bg: "#282c34"
fg: "#abb2bf"

shared/colors.yaml

theme:
colors:
editor.background: $(std.bg)
editor.foreground: $(std.fg)

shared/tokenColors.yaml

theme:
tokenColors:
- name: Keywords
scope: keyword
settings:
foreground: $$cyan

shared/semanticTokenColors.yaml

theme:
semanticTokenColors:
variable.declaration:
foreground: $(std.fg)
fontStyle: italic
function.declaration:
foreground: $(accent)
fontStyle: bold
"string:escape": $$cyan