Skip to content

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.

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"
}
}
]
}
FieldTypeRequiredPurpose
namestringNoHuman-readable label (not used by VS Code at runtime)
scopestringYesTextMate scope selector (comma-separated for multiple)
settingsobjectYesStyling to apply

The settings object supports two properties:

PropertyTypeExamplePurpose
foregroundhex string"#c678dd"Text colour
fontStylestring"italic", "bold", "underline", "bold italic"Font decoration (space-separated for combinations)

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:

ScopeWhat It Matches
commentAll comments
keywordLanguage keywords (if, return, import, class)
storageStorage modifiers (const, let, var, static)
stringString literals
constantConstants (true, false, null, numbers)
entity.name.functionFunction/method names at declaration
entity.name.classClass names
entity.name.typeType names
variableVariables
variable.parameterFunction parameters
punctuationBrackets, commas, semicolons
support.functionBuilt-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.

VS Code evaluates tokenColors rules top to bottom and stops at the first match. This has two important consequences:

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" }
}
]
}

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.

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.

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.

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.

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.

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 equivalent
theme:
tokenColors:
- name: Comments
scope: comment
settings:
foreground: $(std.fg.inactive)
fontStyle: italic

The 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.