TanStack Highlight separates tokenization from presentation. Languages emit semantic classes; CSS decides colors and font styles.
const result = highlighter.highlight(code, { lang: 'tsx' })type HighlightResult = {
code: string
lang: string
tokens: Array<HighlightToken>
html: string
}code is the original input. Concatenating every token.value reconstructs it exactly.
Without line wrappers:
<pre class="th-code th-code--tsx" data-language="tsx">
<code>
<span class="th-token th-keyword">const</span>
...
</code>
</pre>With line numbers or line decorations:
<pre class="th-code th-code--tsx th-code--line-numbers" data-language="tsx">
<code>
<span class="th-line" data-line="1">...</span>
</code>
</pre>Line wrappers are omitted unless they are needed, reducing the normal output size.
| Class | Typical use |
|---|---|
| th-attr | Markup attributes |
| th-code-inline | Inline Markdown or unparsed fenced code |
| th-command | Shell and Docker commands |
| th-comment | Comments |
| th-deleted | Deleted diff lines |
| th-function | Function declarations and calls |
| th-heading | Markdown headings and TOML tables |
| th-inserted | Inserted diff lines |
| th-keyword | Language keywords and directives |
| th-link | Markdown links |
| th-literal | Booleans, nulls, regex literals |
| th-meta | Diff/fence/protocol metadata |
| th-number | Numeric values |
| th-operator | Template boundaries and diagram arrows |
| th-property | Object properties, headers, config keys |
| th-selector | CSS selectors |
| th-string | Strings and protected scalar bodies |
| th-tag | Markup tags |
| th-type | Type names and annotations |
| th-variable | Shell, CSS, and config variables |
Every token span also receives th-token.
Use tokenize() for another renderer:
const { tokens } = highlighter.tokenize(code, { lang: 'ts' })Use renderTokens() to convert tokens and decorations into render nodes:
import { renderTokens } from '@tanstack/highlight/core'
const nodes = renderTokens(tokens, {
lineNumbers: true,
decorations,
})renderNodesToHtml(nodes) converts those nodes to escaped inline markup. tokensToHast() from the Markdown entry converts tokens to a complete HAST <pre><code> tree.
This protects the generated code block. It does not sanitize unrelated raw HTML in a Markdown document.
You can skip createThemeCss() and target classes directly:
.th-code {
overflow-x: auto;
background: #fff;
color: #24292f;
}
.th-keyword { color: #cf222e; font-weight: 600; }
.th-string { color: #0a3069; }
.th-comment { color: #6e7781; font-style: italic; }Theme objects cover colors only. Font style, contrast policy, spacing, line highlighting, and copy controls remain application CSS and UI concerns.