Skip to content

FIX: myst-nb 1.4+ compatibility, inline_literal_box option, and --qe-literal-color#373

Merged
mmcky merged 10 commits intomainfrom
fix/mystnb-dark-mode-compat
Mar 8, 2026
Merged

FIX: myst-nb 1.4+ compatibility, inline_literal_box option, and --qe-literal-color#373
mmcky merged 10 commits intomainfrom
fix/mystnb-dark-mode-compat

Conversation

@mmcky
Copy link
Copy Markdown
Contributor

@mmcky mmcky commented Mar 7, 2026

Summary

Fix compatibility with myst-nb 1.4.0+ by setting the data-theme attribute, increasing CSS specificity for custom syntax highlighting, adding a configurable inline_literal_box option, and integrating inline code literal color into the text color scheme system.

Problem

myst-nb 1.4.0 (executablebooks/MyST-NB#693) changed its CSS dark mode detection from html[data-theme="dark"] selectors to a CSS space-toggle technique with @media (prefers-color-scheme) fallback. Since quantecon-book-theme uses body.dark-theme class for dark mode (not data-theme attribute), myst-nb never detects the theme's mode and falls through to the OS color scheme preference — causing dark code cell backgrounds on a light-themed site.

This was temporarily worked around by pinning myst-nb<1.4.0 in downstream projects (see QuantEcon/lecture-python.myst#825).

Changes

1. Set data-theme on <html> (the standard signal)

Set data-theme on <html> (the standard signal used by pydata-sphinx-theme, Furo, and sphinx-book-theme) in three places:

  1. layout.html early script — sets data-theme="light" by default, or "dark" if dark mode was previously saved, preventing flash of incorrect styles
  2. theme-settings.js setContrast() — syncs data-theme on page load
  3. theme-settings.js click handler — toggles data-theme when the contrast button is clicked

The existing body.dark-theme class mechanism is preserved for backward compatibility.

2. Increase CSS specificity for custom code highlighting

Setting data-theme activated pydata-sphinx-theme's Pygments CSS rules, which are all scoped to html[data-theme="light/dark"] .highlight (specificity (0,3,1)). Our custom highlighting in _code.scss and _syntax.scss used :where() for zero specificity, so pydata's rules overrode all our custom token colors.

Fix: Replaced :where(body:not(.use-pygments-style)) with html body:not(.use-pygments-style) giving specificity (0,3,2) — beating pydata's (0,3,1).

3. Add inline_literal_box option

pydata-sphinx-theme applies background, border, and padding to code.literal elements. A new theme option controls this:

  • inline_literal_box: False (default) — strips the box styling to match our original look
  • inline_literal_box: True — re-enables pydata's box/border/padding on inline code
html_theme_options = {
    "inline_literal_box": True,  # enable inline code boxes
}

4. Add --qe-literal-color to text color scheme system

Integrated inline code literal (code.literal) color into the color scheme system alongside emphasis, strong, and definition colors:

Scheme Light Mode Dark Mode
seoul256 (default) #af5f5f muted rust #d78787 soft rose
gruvbox #9d0006 dark red #fb4934 bright red
none inherits text color inherits text color

Overridable via --qe-literal-color CSS variable in a custom stylesheet.

Files Changed

  • layout.htmldata-theme in flash-prevention script + inline-literal-box body class
  • theme-settings.jsdata-theme sync in setContrast() and click handler
  • _code.scss — CSS specificity fix + code.literal box override
  • _syntax.scss — CSS specificity fix
  • _colors.scss — Seoul256 and Gruvbox literal color variables
  • _base.scsscode.literal color rule
  • _dark-theme.scss — dark mode code.literal color
  • _color-schemes.scss — gruvbox and none scheme literal rules
  • theme.confinline_literal_box option
  • __init__.pyinline_literal_box context variable
  • code-highlighting.md — inline code box + color documentation
  • text-color-schemes.md — literal color in scheme tables and examples

Testing

  • Pre-commit checks pass (pre-commit run --all-files)
  • Webpack build succeeds (npm run build)
  • Visual snapshots need regeneration (/update-snapshots)

Closes

Closes #372

myst-nb 1.4.0 (PR executablebooks/MyST-NB#693) changed its dark mode CSS
from html[data-theme="dark"] selectors to a CSS space-toggle technique
that falls back to @media (prefers-color-scheme) when no data-theme
attribute is present.

Since quantecon-book-theme uses body.dark-theme class (not data-theme)
for dark mode, mystnb never detects the theme mode and falls through to
the OS color scheme preference, causing dark code cell backgrounds on
light-themed sites for users with OS dark mode enabled.

Fix: Set data-theme="light" on <html> by default and toggle it to
data-theme="dark" when the contrast button is activated. This is the
standard mechanism used by pydata-sphinx-theme, Furo, and
sphinx-book-theme.

Closes #372
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 7, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@3ffc996). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/quantecon_book_theme/__init__.py 75.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #373   +/-   ##
=======================================
  Coverage        ?   46.21%           
=======================================
  Files           ?        2           
  Lines           ?      409           
  Branches        ?        0           
=======================================
  Hits            ?      189           
  Misses          ?      220           
  Partials        ?        0           
Flag Coverage Δ
pytests 46.21% <75.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a compatibility issue with myst-nb 1.4.0+ where code cell backgrounds would appear dark on light-themed sites for users with OS dark mode enabled. The root cause is that myst-nb 1.4+ changed its dark mode detection to use html[data-theme="dark"] and @media (prefers-color-scheme) fallback, but this theme only used body.dark-theme class — so myst-nb would fall through to the OS preference. The fix sets the data-theme attribute on <html> to explicitly signal the theme's current mode.

Changes:

  • Sets data-theme attribute on <html> in three synchronized locations: the inline early script (FOUC prevention), the setContrast() function on page load, and the contrast toggle click handler.
  • Defaults to data-theme="light" in the catch block of the early script to ensure a safe fallback.
  • Preserves the existing body.dark-theme class mechanism for backward compatibility.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/quantecon_book_theme/theme/quantecon_book_theme/layout.html Adds data-theme attribute sync to the inline early script that prevents FOUC, including light default in else/catch branches
src/quantecon_book_theme/assets/scripts/theme-settings.js Adds data-theme attribute sync in setContrast() and in the contrast button click handler

You can also share your feedback on Copilot code review. Take the survey.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 7, 2026

🎭 Visual Regression Test Results

passed  45 passed
skipped  1 skipped

Details

stats  46 tests across 1 suite
duration  1 minute, 2 seconds
commit  1a0c1d4

Skipped tests

mobile-chrome › theme.spec.ts › Theme Features › f-string interpolation styling

@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 7, 2026

/update-snapshots

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 7, 2026

✅ All visual snapshots have been regenerated and committed to this PR.

📦 Download snapshot-update-diff artifact to review before/after images.

@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 7, 2026

  • new fixtures appear to show differences in syntax highlighting
  • verify if syntax highlighting comes from mystnb updates in 1.4.0
  • retain current highlighter preferences

…eme attribute

pydata-sphinx-theme has a rule scoped to html[data-theme=light] that sets
.highlight .nf color to #0078a1 with !important. This was dormant before we
set data-theme on <html>. It overrode our custom function name color (#06287e)
from _code.scss since :where() has zero specificity.

Add a counter-rule with higher specificity to preserve our custom highlighting
when qetheme_code_style is enabled.
@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 7, 2026

/update-snapshots

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 7, 2026

@github-actions github-actions bot temporarily deployed to pull request March 7, 2026 23:11 Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 7, 2026

✅ All visual snapshots have been regenerated and committed to this PR.

📦 Download snapshot-update-diff artifact to review before/after images.

…ments rules

pydata-sphinx-theme's overwrite_pygments_css scopes ALL Pygments rules to
html[data-theme="light"] and html[data-theme="dark"] at specificity (0,3,1).
Our :where() wrapper gave zero specificity, so setting data-theme activated
pydata's Pygments rules which overrode ALL our custom token colors.

Replace :where(body:not(.use-pygments-style)) with
html body:not(.use-pygments-style) which gives specificity (0,3,2),
beating pydata's (0,3,1). Applied to both _code.scss and _syntax.scss.

Remove the previous .nf-specific override since higher base specificity
now handles all tokens.
@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 8, 2026

/update-snapshots

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 8, 2026

✅ All visual snapshots have been regenerated and committed to this PR.

📦 Download snapshot-update-diff artifact to review before/after images.

@mmcky mmcky changed the title FIX: Set data-theme attribute on <html> for myst-nb 1.4+ compatibility FIX: Set data-theme attribute and increase CSS specificity for myst-nb 1.4+ compatibility Mar 8, 2026
Add configurable theme option (default: False) that controls whether
inline code elements (code.literal) show pydata-sphinx-theme's background
box and border styling. When False, the boxes are stripped to match the
theme's original look. Set inline_literal_box: True in html_theme_options
to re-enable the box styling.
@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 8, 2026

/update-snapshots

@mmcky mmcky changed the title FIX: Set data-theme attribute and increase CSS specificity for myst-nb 1.4+ compatibility FIX: myst-nb 1.4+ compatibility — data-theme attribute, CSS specificity, and inline_literal_box option Mar 8, 2026
@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 8, 2026

/update-snapshots

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 8, 2026

✅ All visual snapshots have been regenerated and committed to this PR.

📦 Download snapshot-update-diff artifact to review before/after images.

Integrate inline code literal (code.literal) color into the color scheme
system alongside emphasis, strong, and definition colors:

- Seoul256: #af5f5f (muted rust) / #d78787 (soft rose dark)
- Gruvbox: #9d0006 (dark red) / #fb4934 (bright red dark)
- None: inherits text color

Overridable via --qe-literal-color CSS variable.
@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 8, 2026

/update-snapshots

@mmcky mmcky changed the title FIX: myst-nb 1.4+ compatibility — data-theme attribute, CSS specificity, and inline_literal_box option FIX: myst-nb 1.4+ compatibility, inline_literal_box option, and --qe-literal-color Mar 8, 2026
@github-actions github-actions bot temporarily deployed to pull request March 8, 2026 04:19 Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 8, 2026

✅ All visual snapshots have been regenerated and committed to this PR.

📦 Download snapshot-update-diff artifact to review before/after images.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 20 changed files in this pull request and generated 2 comments.


You can also share your feedback on Copilot code review. Take the survey.

@mmcky
Copy link
Copy Markdown
Contributor Author

mmcky commented Mar 8, 2026

Both Copilot review suggestions applied in commit 1a0c1d4: added contrast ratio info to Gruvbox literal color comments and fixed the leading space in the body class template logic.

@github-actions github-actions bot temporarily deployed to pull request March 8, 2026 04:58 Inactive
@mmcky mmcky merged commit 7f3a96d into main Mar 8, 2026
10 checks passed
@mmcky mmcky deleted the fix/mystnb-dark-mode-compat branch March 8, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Code block background renders dark in light mode (cell_input)

2 participants