Desktop/web: chat markdown ignores the theme's `--markdown-*` color tokens — output renders monochrome while the TUI colors it
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 62/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- css, electron, typescript
- Domain
- frontend
Research direction
Start with packages/session-ui/src/components/markdown.css, where h1–h3, strong/b, and inline code set color to var(--v2-text-text-base) and em/i has no rule. Check that the --markdown-* tokens from packages/ui/src/styles/theme.css resolve in the running app before editing. Done when headings, bold, emphasis, inline code, list markers, and blockquotes take their theme tokens with fallbacks, and the change is checked visually across at least two themes in dark and light mode.
Written by the indexing model from the issue text.
Description
Description
The desktop/web theme pipeline generates a complete set of --markdown-* CSS custom properties for every theme — --markdown-heading, --markdown-strong, --markdown-emph, --markdown-code, --markdown-link, --markdown-link-text, --markdown-list-item, --markdown-list-enumeration, --markdown-block-quote, --markdown-horizontal-rule, etc. (defaults also exist in packages/ui/src/styles/theme.css).
However, the chat markdown component (packages/session-ui/src/components/markdown.css) does not consume them. Headings, bold, inline code, and emphasis are all styled with the base text color, so chat output in Desktop/web renders effectively monochrome. The TUI renders the same markdown elements in color via its theme's markdown tokens, so the same session reads very differently in the two clients.
Verified on Desktop 2.2.5. From the current packages/session-ui/src/components/markdown.css:
h1 { font-size: 17px; color: var(--v2-text-text-base); ... }
h2 { font-size: 15px; color: var(--v2-text-text-base); ... }
h3 { font-size: 13px; color: var(--v2-text-text-base); ... }
strong, b { color: var(--v2-text-text-base); font-weight: var(--font-weight-bold); }
:not(pre) > code { color: var(--v2-text-text-base); ... }
/* em/i: not styled at all — inherits body color */
Meanwhile the generated theme CSS for the active theme does define the tokens. Example — tokyonight, dark mode, Desktop 2.2.5 (observed as computed CSS custom properties in the running app):
--markdown-heading: #d0dffe;
--markdown-text: #c4cefb;
--markdown-link: #d0dffe;
--markdown-link-text: #bfe5fc;
--markdown-code: #a8fc1c;
--markdown-block-quote: #fdd8a5;
--markdown-emph: #fdd8a5;
--markdown-strong: #fdd6bf;
--markdown-horizontal-rule: #3c4052;
--markdown-list-item: #d0dffe;
--markdown-list-enumeration: #bfe5fc;
None of these variables are referenced by the chat markdown component, so they are currently dead values.
Steps to reproduce
- Open OpenCode Desktop (2.2.5), any built-in theme, dark mode, no plugins.
- Ask the agent a question that produces a markdown reply containing a heading, bold text, inline code, a bulleted/numbered list, and a blockquote.
- Open the same session in the TUI (
opencodeCLI). - Compare the two renderings.
Expected Behavior
Chat markdown in Desktop/web consumes the theme's markdown tokens, with safe fallbacks, e.g.:
h1, h2, h3, h4, h5, h6 { color: var(--markdown-heading, var(--v2-text-text-base)); }
strong, b { color: var(--markdown-strong, var(--v2-text-text-base)); }
em, i { color: var(--markdown-emph, inherit); }
:not(pre) > code { color: var(--markdown-code, var(--v2-text-text-base)); }
blockquote { color: var(--markdown-block-quote, var(--v2-text-text-muted)); }
ul > li::marker { color: var(--markdown-list-item, currentColor); }
ol > li::marker { color: var(--markdown-list-enumeration, currentColor); }
hr { border-color: var(--markdown-horizontal-rule, var(--v2-border-border-base)); }
This would restore parity with the TUI, where these elements are colored per theme.
Actual Behavior
All of these elements render in the same base text color as body prose (only font size/weight differ), regardless of theme. Chat output looks monochrome compared to the TUI.
Two additional observations that may be worth addressing in the same pass:
- Desktop theme files only define a palette + syntax overrides, so the
--markdown-*values are auto-derived — some derived values look unpolished (e.g. tokyonight dark derives--markdown-code: #a8fc1c, a harsh neon green). Hand-tuning the derivation (or adding markdown overrides to the desktop theme schema) may be needed alongside wiring the tokens. hris currently invisible (border: none; height: 0), so the--markdown-horizontal-ruletoken cannot express itself at all.
Workaround
A GUI plugin contributing a Style that wires these elements to the existing variables recolors the timeline immediately with no app changes — which also demonstrates the fix is low-risk. Happy to share the ~40 lines of CSS if useful.
Environment
- OpenCode version: Desktop 2.2.5 (Electron 44.9.1; bundled CLI 2.2.5)
- OS: macOS 27.0.1 (26A434), Apple silicon
- Terminal: N/A (Desktop app; comparison made against the TUI in iTerm/Terminal)
- Plugins: none required — reproduces on a clean install with any built-in theme, in both dark and light modes
Related
- #16046 — Markdown headings in Desktop chat render only as bold (same root cause; closed as not planned)
- #43597 — bold rendering fixed via font weight in v2.0.22, but color still identical to body text (maintainer asked for a new issue with v2 details)
- #15141 — TUI heading hierarchy
- #30542 — marked duplicate of #16046
- Dominant language
- TypeScript
- Stars
- 224k
- Forks
- 30k
- Avg merge
- 6h 48m
- Merged PRs (30d)
- 490
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from anomalyco/opencode
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
anomalyco/opencode#60584 · 2 comments ·
Maintainers usually reply within 1 day
-
core: OpenRouter BYOK sessions record cost = 0 since v2.2.0 (ignores cost_details.upstream_inference_cost)Possibly taken @tneemo claimed this 3 days ago. Openreproduced
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
anomalyco/opencode#60558 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
anomalyco/opencode#60541 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
anomalyco/opencode#60529 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
anomalyco/opencode#60469 · 2 comments ·
Maintainers usually reply within 1 day
All issues in anomalyco/opencode
Similar issues
-
Remove unused dependenciesPossibly taken @alastair-smith claimed this today. Openchore other
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
alastair-smith/card-games#384 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
code-yeongyu/senpi#5571 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
nexu-io/open-design#9262 · 1 comment ·
Maintainers usually reply within 1 day
-
friction
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
kentcdodds/kody#4753 ·
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 62/100
lingdojo/kana-dojo#33508 · 1 comment · 5 reactions ·
Maintainers usually reply within 1 day