Summary
toolcraft-design should add lightweight, opt-in syntax highlighting to renderMarkdownHtml for fenced code blocks.
The API should be only an on/off toggle. No modes, themes, inline-style mode, custom callback, or bundled CSS requirement.
Proposed API
renderMarkdownHtml(markdown, { syntaxHighlight: true })
Default behavior stays exactly as it is today:
renderMarkdownHtml(markdown)
continues to render escaped code inside:
<pre><code class="language-js">const x = "hello";</code></pre>
Desired behavior
When syntaxHighlight: true is set, fenced code blocks should be tokenized based on the fence language and rendered with safe inline <span> wrappers using stable classes:
<pre><code class="language-js"><span class="tc-token-keyword">const</span> x = <span class="tc-token-string">"hello"</span>;</code></pre>
If the consumer provides no CSS, this should still look like normal code because plain <span> elements have no default visual styling. Consumers that want highlighting can style the token classes themselves.
Toolcraft should not need to ship or inject CSS for this feature.
Constraints
- Default remains off and byte-for-byte behavior should stay as close to current output as practical.
- The only public configuration should be the boolean toggle.
- Source text must still be escaped; only Toolcraft-generated
<span> wrappers should be emitted as HTML.
- Do not use tags with default visual styling like
<strong>, <em>, <q>, etc. Use neutral spans.
- Preserve whitespace exactly inside code blocks.
- Keep it lightweight. Avoid pulling in large grammar/theme systems unless there is a strong reason.
Initial language scope
A simple tokenizer is enough to start. Useful first targets:
js, ts, jsx, tsx
json
yaml, yml
css
sh, bash
python
sql
Unknown languages can fall back to the current escaped plain code output.
Why
Consumers like claude-artifacts render Markdown/YAML/CSV/JSON/source files into Claude artifacts using renderMarkdownHtml. The renderer already preserves class="language-*"; adding an opt-in span-based highlighter in Toolcraft keeps the feature in the right layer and avoids consumer-side HTML post-processing.
The key design point: classes mode does not look broken without CSS, because spans are visually neutral. It only becomes highlighted when a consumer stylesheet defines the token classes.
Acceptance criteria
renderMarkdownHtml(markdown) keeps current code-block rendering by default.
renderMarkdownHtml(markdown, { syntaxHighlight: true }) emits token spans for supported fenced languages.
- No CSS is automatically bundled, injected, or required.
- Output remains safe HTML.
- Tests cover escaping, whitespace preservation, unknown-language fallback, and at least JS plus one data language such as JSON/YAML.
Summary
toolcraft-designshould add lightweight, opt-in syntax highlighting torenderMarkdownHtmlfor fenced code blocks.The API should be only an on/off toggle. No modes, themes, inline-style mode, custom callback, or bundled CSS requirement.
Proposed API
Default behavior stays exactly as it is today:
continues to render escaped code inside:
Desired behavior
When
syntaxHighlight: trueis set, fenced code blocks should be tokenized based on the fence language and rendered with safe inline<span>wrappers using stable classes:If the consumer provides no CSS, this should still look like normal code because plain
<span>elements have no default visual styling. Consumers that want highlighting can style the token classes themselves.Toolcraft should not need to ship or inject CSS for this feature.
Constraints
<span>wrappers should be emitted as HTML.<strong>,<em>,<q>, etc. Use neutral spans.Initial language scope
A simple tokenizer is enough to start. Useful first targets:
js,ts,jsx,tsxjsonyaml,ymlcsssh,bashpythonsqlUnknown languages can fall back to the current escaped plain code output.
Why
Consumers like
claude-artifactsrender Markdown/YAML/CSV/JSON/source files into Claude artifacts usingrenderMarkdownHtml. The renderer already preservesclass="language-*"; adding an opt-in span-based highlighter in Toolcraft keeps the feature in the right layer and avoids consumer-side HTML post-processing.The key design point: classes mode does not look broken without CSS, because spans are visually neutral. It only becomes highlighted when a consumer stylesheet defines the token classes.
Acceptance criteria
renderMarkdownHtml(markdown)keeps current code-block rendering by default.renderMarkdownHtml(markdown, { syntaxHighlight: true })emits token spans for supported fenced languages.