Before submitting
Area
apps/desktop
Problem or use case
When a thread discusses colors, the values arrive as bare inline code. A line like "#FFB3C6 on cream #FDF6E3 is a small step in value" tells you nothing about what either color actually looks like, so reviewing a palette, a set of theme tokens, or a diff of design values means copying each literal out into a separate tool one at a time.
Code editors solved this a long time ago — VS Code ships color decorators, JetBrains shows a gutter swatch, Zed renders inline swatches, Sublime has ColorHelper, Neovim has nvim-colorizer. AI chat clients generally have not followed, so the transcript is the one place in the workflow where a color is still just text.
Proposed solution
In the chat transcript, when an inline code span is exactly a CSS color literal, render a small swatch chip immediately before the text — the same convention editors use.
- Supported notations: 3/4/6/8-digit hex, and
rgb() / rgba() / hsl() / hsla() / hwb() / lab() / lch() / oklab() / oklch().
- Translucent colors (
#FFB3C680, rgba(20 24 40 / 0.35)) sit on a checkerboard so the alpha reads.
- The swatch is decorative and
aria-hidden, so copying the message out is unchanged.
- Spans that merely contain a color stay plain:
#FFB3C6 on cream, red, abcdef.
- Existing file-path chips keep precedence, so
apps/web/src/index.css is unaffected.
Why this matters
Anyone doing design, theming, or CSS work with an agent can read a palette straight out of the conversation instead of round-tripping every value through a color picker. It is most useful exactly when the agent is explaining a set of related colors — the case where copying each one out is slowest.
It is also a small differentiator: this is standard in editors and absent from essentially every AI chat client.
Smallest useful scope
Hex literals only, in the web chat markdown renderer (apps/web/src/components/ChatMarkdown.tsx). Hex covers the large majority of colors that appear in prose. Functional notations and the alpha checkerboard can follow.
Alternatives considered
Prior art for the interaction: VS Code color decorators, JetBrains gutter swatches, Zed inline swatches, Sublime ColorHelper, nvim-colorizer.
Considered and rejected: matching bare CSS color keywords (red, tan, salmon). They appear in prose far more often than as color values, so the false-positive rate is not worth it.
Today's workaround is pasting each literal into a color picker.
Risks or tradeoffs
- False positives. Requiring the span to be exactly a color literal, and skipping bare keywords, keeps this narrow.
- Line height. Making the
<code> an atomic inline (inline-flex) causes its padding and line-height to count toward the line box, so every line holding a color gets taller than its neighbours. The swatch has to be an inline-block inside a still-inline <code>, the way .chat-markdown-link-favicon already handles link favicons.
- Injection. Whatever is matched ends up in a style attribute, so the value needs to be shape-validated by regex (not merely trusted) before it is used as a fill.
- Mobile.
apps/mobile uses a separate native markdown pipeline (modules/t3-markdown-text) and would need its own change; this request is web only.
Examples or references
Before / after — screenshots below.
Contribution
Before submitting
Area
apps/desktop
Problem or use case
When a thread discusses colors, the values arrive as bare inline code. A line like "
#FFB3C6on cream#FDF6E3is a small step in value" tells you nothing about what either color actually looks like, so reviewing a palette, a set of theme tokens, or a diff of design values means copying each literal out into a separate tool one at a time.Code editors solved this a long time ago — VS Code ships color decorators, JetBrains shows a gutter swatch, Zed renders inline swatches, Sublime has ColorHelper, Neovim has nvim-colorizer. AI chat clients generally have not followed, so the transcript is the one place in the workflow where a color is still just text.
Proposed solution
In the chat transcript, when an inline code span is exactly a CSS color literal, render a small swatch chip immediately before the text — the same convention editors use.
rgb() / rgba() / hsl() / hsla() / hwb() / lab() / lch() / oklab() / oklch().#FFB3C680,rgba(20 24 40 / 0.35)) sit on a checkerboard so the alpha reads.aria-hidden, so copying the message out is unchanged.#FFB3C6 on cream,red,abcdef.apps/web/src/index.cssis unaffected.Why this matters
Anyone doing design, theming, or CSS work with an agent can read a palette straight out of the conversation instead of round-tripping every value through a color picker. It is most useful exactly when the agent is explaining a set of related colors — the case where copying each one out is slowest.
It is also a small differentiator: this is standard in editors and absent from essentially every AI chat client.
Smallest useful scope
Hex literals only, in the web chat markdown renderer (
apps/web/src/components/ChatMarkdown.tsx). Hex covers the large majority of colors that appear in prose. Functional notations and the alpha checkerboard can follow.Alternatives considered
Prior art for the interaction: VS Code color decorators, JetBrains gutter swatches, Zed inline swatches, Sublime ColorHelper, nvim-colorizer.
Considered and rejected: matching bare CSS color keywords (
red,tan,salmon). They appear in prose far more often than as color values, so the false-positive rate is not worth it.Today's workaround is pasting each literal into a color picker.
Risks or tradeoffs
<code>an atomic inline (inline-flex) causes its padding and line-height to count toward the line box, so every line holding a color gets taller than its neighbours. The swatch has to be an inline-block inside a still-inline<code>, the way.chat-markdown-link-faviconalready handles link favicons.apps/mobileuses a separate native markdown pipeline (modules/t3-markdown-text) and would need its own change; this request is web only.Examples or references
Before / after — screenshots below.
Contribution