[FEATURE] Custom themes should be able to override the diff syntax-highlighting palette

Status Open
Maintainer reply None cached
Activity 3 comments · opened Aug 11, 2026

Problem Statement

Custom themes ("theme": "custom:my-theme" with a theme JSON in ~/.claude/themes/) can override diff backgrounds (diffAdded, diffRemoved, …) and all UI colors, but the syntax-highlighting palette used inside diffs is hardcoded in the binary and ignores the theme entirely:

  • Any theme whose name contains "dark" gets a fixed Monokai Extended scope palette; every other theme gets a fixed GitHub-light palette (selection is by substring match on the theme name, not the theme's base field).
  • In both palettes, comment and meta tokens are a low-contrast grey — rgb(117,113,94) on dark, rgb(150,152,150) on light. On the added-line green background (and on dimmed/soft-contrast backgrounds generally) comments are very hard to read.
  • None of the theme override keys apply to these scope colors, and CLAUDE_CODE_SYNTAX_HIGHLIGHT / syntaxHighlightingDisabled is all-or-nothing: the only way to get readable comments is to lose syntax highlighting completely.

Observed in v2.1.227 (macOS arm64).

Proposed Solution

Let custom theme JSON files optionally override syntax scope colors, falling back to the current built-in palettes:

{
  "name": "GitHub Dark Dimmed",
  "base": "dark",
  "overrides": { "...": "existing keys" },
  "syntax": {
    "comment": "#768390",
    "keyword": "#f47067",
    "string": "#96d0ff"
  }
}

Related improvements while in this area:

  1. Pick the built-in palette from the custom theme's base field rather than substring-matching the theme name (a custom theme named e.g. custom:nightfall with "base": "dark" currently gets the light palette).
  2. Consider raising the default comment/meta contrast — grey-on-green added lines fail WCAG contrast in both built-in palettes.

Alternative Solutions

  • syntaxHighlightingDisabled: true — works but removes all highlighting.
  • Patching the color literals in the binary — works but is reverted by every auto-update.

Additional Context

Related: #48636 asks for customizable snippet colors generally; this request is scoped to the diff renderer's palette and to making the existing custom-theme system cover it, which didn't exist when that issue was filed.

View original on GitHub ↗

3 Comments

jrista · 14 days ago

Want to second the ability to fully customize the code syntax highlighting. Not just the diff lines, ALL code, of all kinds. Its odd that this isn't supported, as its one of the main things everyone wants to customize. I have a fairly specific look and feel in all of my terminals...whites, grays, soft blues, oranges, tans, browns. The Monokai colored source code in Claude Code stands out like a sore thumb! :P Would be great to be given some configuration/theming capabilities to set up, install, and select custom syntax highlighting themes so we can better immerse our CC instances into the rest of our color-managed environments.

Thanks!

breferrari · 12 days ago

Reproduces on v2.1.234 too, and this diagnosis matches what I found independently while building a custom theme (base: "dark") named vesper.json: diffAdded/diffRemoved backgrounds applied correctly, but the in-diff syntax colors stayed fixed to the Monokai-dark scope palette regardless of the theme's own hues — confirmed by swapping diffAdded/diffRemoved to neon values and watching only the background change, never the text. Also relates to #48636, which is the more general version of this ask; this one is the sharper, more actionable scope.

The syntax: {...} override block proposed here would resolve it cleanly, and would also fix the substring-match issue for any custom theme whose slug doesn't happen to contain "dark" but sets "base": "dark".

pawel-kotowski · 1 day ago

One more case worth folding into this: "theme": "auto" silently locks the syntax palette, with no way out short of giving up auto-switching.

Confirmed on v2.1.251 (macOS arm64). auto resolves to the bare strings "dark" / "light" before the palette selector ever runs:

// theme resolution
if (e === "auto") return mG();            // -> cachedSystemTheme() ?? <detect from terminal bg> ?? "dark"

// syntax palette selection
if (e.includes("ansi")) return "ansi";
if (e.includes("dark")) return "Monokai Extended";
return "GitHub";

Two consequences:

  1. auto can never resolve to a custom theme — it only ever yields "dark" or "light", so even once syntax: {} overrides land, they'd be unreachable for anyone who wants light/dark to follow the system. A custom theme is a fixed choice by definition.
  2. When terminal-background detection fails, mG() falls back to "dark", so users land on Monokai Extended without having chosen a dark theme at all.

Today the only escapes are picking dark-ansi/light-ansi (syntax colors come from the terminal's 16 ANSI colors, but auto-switching is gone) or syntaxHighlightingDisabled: true. Neither preserves "follow the system and use my palette", which is the common case for anyone whose terminal already switches with macOS appearance.

So alongside the proposed syntax: {} block, it'd help if auto could be pointed at a pair of custom themes rather than only the built-in dark/light — e.g.:

{ "theme": "auto", "themeAuto": { "dark": "custom:vesper", "light": "custom:vesper-light" } }

Otherwise the theming system stays mutually exclusive with system-appearance following.

Minor note on point 1 of the original post (palette picked by substring match on the name rather than the theme's base): on 2.1.251 the resolver does appear to map a custom slug through its base field before the substring match, so that specific sub-issue may have been fixed since 2.1.227 — worth re-checking before it's actioned. The core complaint (scope colors are hardcoded and unreachable from overrides) is unchanged: the theme loader keeps an override key only when it already exists in the base palette, and that palette is UI + diff colors only.