Desktop/web: chat markdown ignores the theme's `--markdown-*` color tokens — output renders monochrome while the TUI colors it

Open Beginner friendly
#61,221 2 comments 0 reactions 0 assignees View on GitHub

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
  1. Open OpenCode Desktop (2.2.5), any built-in theme, dark mode, no plugins.
  2. Ask the agent a question that produces a markdown reply containing a heading, bold text, inline code, a bulleted/numbered list, and a blockquote.
  3. Open the same session in the TUI (opencode CLI).
  4. 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:

  1. 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.
  2. hr is currently invisible (border: none; height: 0), so the --markdown-horizontal-rule token 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

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.

More from anomalyco/opencode

All issues in anomalyco/opencode

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.