Token Colors
tokenColors is the syntax highlighting layer. It controls how source code is painted — keywords, strings, comments, function names, operators, and everything else that makes code readable at a glance.
Structure
Section titled “Structure”tokenColors is an array of rules. Each rule has three fields:
{ "tokenColors": [ { "name": "Comments", "scope": "comment", "settings": { "foreground": "#5c6370", "fontStyle": "italic" } }, { "name": "Keywords", "scope": "keyword, storage.type", "settings": { "foreground": "#c678dd" } } ]}| Field | Type | Required | Purpose |
|---|---|---|---|
name | string | No | Human-readable label (not used by VS Code at runtime) |
scope | string | Yes | TextMate scope selector (comma-separated for multiple) |
settings | object | Yes | Styling to apply |
The settings object supports two properties:
| Property | Type | Example | Purpose |
|---|---|---|---|
foreground | hex string | "#c678dd" | Text colour |
fontStyle | string | "italic", "bold", "underline", "bold italic" | Font decoration (space-separated for combinations) |
TextMate Scopes
Section titled “TextMate Scopes”VS Code uses TextMate grammars to tokenise source code. Each token in your code is assigned one or more scopes — dot-separated identifiers that describe what the token is.
For example, the keyword if in JavaScript might have the scope keyword.control.conditional.js. A string literal might be string.quoted.double.js.
Common top-level scopes:
| Scope | What It Matches |
|---|---|
comment | All comments |
keyword | Language keywords (if, return, import, class) |
storage | Storage modifiers (const, let, var, static) |
string | String literals |
constant | Constants (true, false, null, numbers) |
entity.name.function | Function/method names at declaration |
entity.name.class | Class names |
entity.name.type | Type names |
variable | Variables |
variable.parameter | Function parameters |
punctuation | Brackets, commas, semicolons |
support.function | Built-in/library functions |
Scopes are hierarchical. keyword.control is a child of keyword. A rule matching keyword will also match keyword.control, keyword.operator, and any other keyword.* scope.
First-Match Semantics
Section titled “First-Match Semantics”VS Code evaluates tokenColors rules top to bottom and stops at the first match. This has two important consequences:
Order Matters
Section titled “Order Matters”If a broad scope appears before a specific scope, the specific rule never fires:
{ "tokenColors": [ { "name": "All Keywords", "scope": "keyword", "settings": { "foreground": "#c678dd" } }, { "name": "Control Keywords", "scope": "keyword.control", "settings": { "foreground": "#e06c75", "fontStyle": "bold" } } ]}The second rule is dead code. keyword matches before keyword.control gets a chance.
Fix: Put specific scopes before broad ones:
{ "tokenColors": [ { "name": "Control Keywords", "scope": "keyword.control", "settings": { "foreground": "#e06c75", "fontStyle": "bold" } }, { "name": "All Keywords", "scope": "keyword", "settings": { "foreground": "#c678dd" } } ]}Comma-Separated Scopes Share Settings
Section titled “Comma-Separated Scopes Share Settings”Multiple scopes in a single rule all receive the same styling:
{ "scope": "keyword, storage.type, storage.modifier", "settings": { "foreground": "#c678dd" }}This is a convenience — it’s equivalent to three separate rules with the same settings.
Gotchas
Section titled “Gotchas”No Background Colour
Section titled “No Background Colour”Unlike colors, the settings object in tokenColors does not support background. You can set foreground and fontStyle only. If you want to highlight a region of code with a background colour, that’s done through colors keys like editor.selectionBackground or through editor decorations, not tokenColors.
fontStyle Resets
Section titled “fontStyle Resets”Setting fontStyle to an empty string ("") explicitly removes all font styles. This is different from omitting fontStyle, which inherits the default. Use this when a broad rule sets italic and you want a more specific rule to undo it.
Scope Specificity Is Not CSS
Section titled “Scope Specificity Is Not CSS”TextMate scope matching is simpler than CSS specificity. There’s no scoring system — it’s purely positional (first match wins). If you’re coming from CSS, forget specificity. Think in terms of rule order.
Language-Specific Scopes
Section titled “Language-Specific Scopes”Some grammars append a language suffix: keyword.control.js, string.quoted.double.python. You can target these specifically, but broad scopes like keyword already match them. Language suffixes are mostly useful when you want one language styled differently from others.
In Sassy
Section titled “In Sassy”Sassy’s tokenColors maps directly to the VS Code structure. The main difference is variable references and colour functions in the values:
# Raw VS Code JSON# {# "name": "Comments",# "scope": "comment",# "settings": {# "foreground": "#5c6370",# "fontStyle": "italic"# }# }
# Sassy equivalenttheme: tokenColors: - name: Comments scope: comment settings: foreground: $(std.fg.inactive) fontStyle: italicThe structure is identical — an array of objects with name, scope, and settings. Sassy resolves the variable references and colour functions, then writes the standard JSON array that VS Code expects.

