quarto-dev / quarto-dev/quarto-cli

Dark syntax highlighting themes don't override light theme's base .sourceCode text color

Open Beginner friendly
#14,099 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accessibility bug themes
Dominant language
JavaScript
Stars
6k
Forks
458
Avg merge
1d 9h
Merged PRs (30d)
41

Description

Description

When using light/dark theme toggling, certain dark syntax highlighting themes (zenburn, espresso) don't generate a base .sourceCode > span text color rule. The light theme's near-black base color persists in dark mode, making code tokens without a specific highlighting class invisible.

Root Cause

The bug is in generateThemeCssClasses(), not in the theme files. The function only emits the .sourceCode > span base color rule when it finds a "Normal" key in "text-styles". It never checks the top-level "text-color" as a fallback.

kate (light theme) has "Normal" in "text-styles":

"text-styles": {
  "Normal": {"text-color": "#1f1c1b", ...}
}

→ Generates .sourceCode > span { color: #1f1c1b; }

zenburn (dark theme) is a valid Pandoc/KDE theme file — it defines "text-color": "#cccccc" at the top level, which is how these theme files can specify the default text color. But it has no "Normal" entry in "text-styles":

{
  "text-color": "#cccccc",
  "background-color": "#303030",
  "text-styles": {
    "Alert": {...},
    "Keyword": {...},
    ...
    // no "Normal" key
  }
}

→ No base .sourceCode > span rule is generated.

Since Quarto layers dark CSS on top of light (// note: dark is layered on light, we don't disable primary!), the light theme's .sourceCode > span { color: #1f1c1b; } persists unchallenged in dark mode.

Note: the triple-stylesheet issue from #13450 is unrelated — Puppeteer testing confirms the quarto-color-scheme-extra sheets are properly disabled by JS on page load and don't cause this problem.

Affected Themes

7 themes are missing "Normal" in text-styles: espresso, haddock, monochrome, none, pygments, tango, zenburn.

Of the dark themes, espresso and zenburn are both affected — they define a top-level text-color but no "Normal" style. Any user-created custom theme with the same valid structure would also break silently.

Reproduction

# _quarto.yml
format:
  html:
    theme:
      light: cosmo
      dark: darkly
    highlight-style:
      light: kate
      dark: zenburn

Any code block with tokens that don't get a specific span class (e.g., plain identifiers, punctuation) will be unreadable in dark mode:

Proposed Fix

In generateThemeCssClasses(), after processing text-styles, fall back to the theme's top-level "text-color" when no "Normal" style was found:

// After the Object.keys(textStyles).forEach loop:
if (!tokenCssByAbbr[""] && themeJson["text-color"]) {
  const cssValues = [`  color: ${themeJson["text-color"]};`, "  font-style: inherit;"];
  toCSS("", "Normal", cssValues);
  ["pre > code.sourceCode > span", "code.sourceCode > span",
   "div.sourceCode,\ndiv.sourceCode pre.sourceCode"]
    .forEach((selector) => {
      otherLines.push(`\n${selector} {`);
      otherLines.push(...cssValues);
      otherLines.push("}\n");
    });
}

Verified by creating a patched zenburn theme with "Normal" added (simulating the fix output) — dark highlighting CSS then emits .sourceCode > span { color: #cccccc; } and all code tokens are readable without any custom SCSS workarounds.

Workaround

body.quarto-dark {
  pre.sourceCode,
  .sourceCode > span,
  code.sourceCode > span {
    color: #dcdccc;
  }
}

Environment

  • Quarto 1.8.27
  • macOS, Chrome/Safari

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/command/render/pandoc-html.ts at generateThemeCssClasses(), then compare the Normal-style handling with the top-level text-color fields in the zenburn and espresso theme files. Use the provided light/dark _quarto.yml reproduction and verify that generated dark-theme CSS includes a readable base span color for themes without a Normal entry.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.