
Description
Style @tanstack/highlight with createThemeCss, createThemeRule, createThemeBaseCss, isolated theme imports, lineNumbers, line decorations, UTF-16 range decorations, and fence annotations. Load for light/dark themes, custom semantic colors, focused lines, diffs, diagnostics, or data hooks.
SKILL.md
Theme and Annotate Code
Setup
Generate light and dark CSS independently from highlighted markup:
import { createThemeCss } from '@tanstack/highlight/theme'
import { githubDarkTheme } from '@tanstack/highlight/themes/github-dark'
import { githubLightTheme } from '@tanstack/highlight/themes/github-light'
export const syntaxThemeCss = createThemeCss({
light: githubLightTheme,
dark: githubDarkTheme,
lightSelector: ':root',
darkSelector: '.dark',
})
The default selectors are :root and .dark; base code and token styles are included unless includeBaseStyles is false.
Core Patterns
Select among named themes
import { createThemeCss } from '@tanstack/highlight/theme'
import { draculaTheme } from '@tanstack/highlight/themes/dracula'
import { githubLightTheme } from '@tanstack/highlight/themes/github-light'
export const syntaxThemeCss = createThemeCss({
themes: [
{
selector: '[data-code-theme="github"]',
theme: githubLightTheme,
},
{
selector: '[data-code-theme="dracula"]',
theme: draculaTheme,
},
],
})
themes mode is mutually exclusive with the light and dark pair mode.
Target renderer-owned code blocks
export const syntaxThemeCss = createThemeCss({
light: githubLightTheme,
dark: githubDarkTheme,
lightSelector: '.markdown-renderer',
darkSelector: '.dark .markdown-renderer',
codeBlockSelector: '.markdown-renderer pre.tm-code',
lineNumbersSelector: '.markdown-renderer .tm-code--line-numbers',
})
The selector defaults are pre.th-code and .th-code--line-numbers. Override both when the surrounding renderer owns different wrapper classes.
Add line numbers and line decorations
import { highlighter } from './highlight'
export const result = highlighter.highlight(
'const first = 1\nconst second = 2\nconst third = 3',
{
lang: 'ts',
lineNumbers: true,
decorations: [
{ lines: 2, className: 'is-focused' },
{ lines: [2, 3], className: 'is-highlighted' },
],
},
)
Line coordinates are one-based and inclusive; decorations activate th-line wrappers even without line numbers.
Attach exact source diagnostics
import { highlighter } from './highlight'
const code = 'const answer = unknownValue'
const start = code.indexOf('unknownValue')
export const result = highlighter.highlight(code, {
lang: 'ts',
decorations: [
{
range: [start, start + 'unknownValue'.length],
className: 'is-error',
data: {
message: 'Unknown identifier',
severity: 2,
},
},
],
})
Character ranges use zero-based, end-exclusive UTF-16 offsets.
Own font styles and annotation presentation in CSS
.th-keyword {
font-weight: 600;
}
.th-comment {
font-style: italic;
}
.th-line--highlighted {
background: rgb(9 105 218 / 10%);
}
.is-error {
text-decoration: underline wavy #cf222e;
}
Theme objects contain colors only; typography, contrast policy, and annotation appearance belong to application CSS.
Common Mistakes
HIGH Duplicating markup for light and dark
Wrong:
import { highlighter } from './highlight'
export const lightHtml = highlighter.highlightToHtml('const value = 1', {
lang: 'ts',
})
export const darkHtml = highlighter.highlightToHtml('const value = 1', {
lang: 'ts',
})
Correct:
import { createThemeCss } from '@tanstack/highlight/theme'
import { githubDarkTheme } from '@tanstack/highlight/themes/github-dark'
import { githubLightTheme } from '@tanstack/highlight/themes/github-light'
import { highlighter } from './highlight'
export const html = highlighter.highlightToHtml('const value = 1', {
lang: 'ts',
})
export const css = createThemeCss({
light: githubLightTheme,
dark: githubDarkTheme,
})
Token classes are theme-independent, so CSS can switch one highlighted tree.
Source: docs/guides/themes.md
MEDIUM Retaining every candidate theme
Wrong:
import { auroraXTheme } from '@tanstack/highlight/themes/aurora-x'
import { draculaTheme } from '@tanstack/highlight/themes/dracula'
import { monokaiTheme } from '@tanstack/highlight/themes/monokai'
export const selectedTheme = {
aurora: auroraXTheme,
dracula: draculaTheme,
monokai: monokaiTheme,
}.dracula
Correct:
import { draculaTheme } from '@tanstack/highlight/themes/dracula'
export const selectedTheme = draculaTheme
Direct subpaths isolate themes only when unused theme modules are not imported.
Source: docs/guides/themes.md
HIGH Hiding an incomplete custom theme
Wrong:
import type { HighlightTheme } from '@tanstack/highlight/theme'
export const theme = {
name: 'docs',
type: 'light',
background: '#ffffff',
foreground: '#24292f',
tokens: {
keyword: '#cf222e',
},
} as HighlightTheme
Correct:
import type { HighlightTheme } from '@tanstack/highlight/theme'
import { githubLightTheme } from '@tanstack/highlight/themes/github-light'
export const theme = {
...githubLightTheme,
name: 'docs',
tokens: {
...githubLightTheme.tokens,
keyword: '#cf222e',
},
} satisfies HighlightTheme
Bypassing the complete token record emits missing CSS variables for semantic classes.
Source: docs/guides/themes.md
HIGH Using character coordinates for lines
Wrong:
import { highlighter } from './highlight'
export const result = highlighter.highlight('first\nsecond\nthird', {
decorations: [{ lines: [0, 2], className: 'is-focused' }],
})
Correct:
import { highlighter } from './highlight'
export const result = highlighter.highlight('first\nsecond\nthird', {
decorations: [{ lines: [1, 3], className: 'is-focused' }],
})
Line ranges are one-based and inclusive, unlike zero-based character ranges.
Source: docs/guides/annotations.md
MEDIUM Assuming annotations include appearance
Wrong:
import { highlighter } from './highlight'
export const result = highlighter.highlight('const value = 1', {
lang: 'ts',
decorations: [{ lines: 1, className: 'th-line--highlighted' }],
})
Correct:
.th-line--highlighted {
background: rgb(9 105 218 / 10%);
}
The renderer emits classes and escaped data attributes but does not style annotation classes.
Source: docs/guides/annotations.md
References
See also: integrate-markdown-pipelines/SKILL.md - fence metadata is the standard source for documentation line annotations.
More skills from the highlight repository
View all 5 skillsconfigure-selective-highlighting
configure selective code highlighting registries
Jul 26ConfigurationFrontendPerformanceextend-language-support
extend language support for code highlighting
Jul 26API DevelopmentEngineeringintegrate-framework-code-blocks
integrate code blocks into web frameworks
Jul 26FrontendReactSSRintegrate-markdown-pipelines
integrate Markdown code highlighting pipelines
Jul 26API DevelopmentFrontendMarkdown
More from TanStack
View publisheraggregation
perform data aggregation in TanStack Table
table
Jul 26Data AnalysisFrontendTanStackapi-not-found
diagnose TanStack Table API errors
table
Jul 26DebuggingFrontendTanStackcell-selection
select rectangular cell ranges in tables
table
Jul 26Data AnalysisTanStackUI Componentsclient-vs-server
manage TanStack Table data pipelines
table
Jul 26Data PipelineFrontendPerformanceTanStackcolumn-faceting
build faceted filter UIs
table
Jul 26Data VisualizationFrontendTanStackcolumn-filtering
implement column filtering in TanStack Table
table
Jul 26Data AnalysisFrontendTanStack