Core Concepts

Annotations

Annotations

Annotations add application classes and data to lines or exact source ranges without changing the token stream.

Line decorations

Line numbers are one-based:

ts
const result = highlighter.highlight(code, {
  lang: 'ts',
  decorations: [
    { lines: 2, className: 'is-focused' },
    { lines: [4, 6], className: 'is-highlighted' },
  ],
})

lines: [4, 6] includes lines 4, 5, and 6.

Line decorations activate th-line wrappers even when lineNumbers is false.

Character-range decorations

Character ranges are zero-based, end-exclusive UTF-16 offsets, matching String.prototype.slice():

ts
const code = `const answer = unknownValue`
const start = code.indexOf('unknownValue')

const result = highlighter.highlight(code, {
  lang: 'ts',
  decorations: [
    {
      range: [start, start + 'unknownValue'.length],
      className: 'is-error',
      data: { message: 'Unknown identifier', severity: 2 },
    },
  ],
})

The renderer splits token boundaries as needed and wraps the selected text with th-decoration plus your classes. Overlapping decorations remain valid nested HTML.

Line numbers

ts
highlighter.highlight(code, {
  lang: 'ts',
  lineNumbers: true,
})

This adds th-code--line-numbers, line wrappers, and data-line. Base theme CSS renders the number with ::before.

Fence annotations

The Markdown helpers recognize common metadata:

markdown
```tsx title="App.tsx" {2,4-6} ins={8} del={9} error={11} lineNumbers
```
SyntaxClass
{2,4-6}th-line--highlighted
highlight={2}th-line--highlighted
ins={2}th-line--inserted
del={2}th-line--deleted
focus={2}th-line--focused
error={2}th-line--error
warning={2}th-line--warning

title, filename, file, and name are accepted title keys. lineNumbers and showLineNumbers enable numbers.

Styling

Annotation classes are intentionally unstyled:

css
.th-line--highlighted { background: rgb(9 105 218 / 10%); }
.th-line--inserted { background: rgb(26 127 55 / 12%); }
.th-line--deleted { background: rgb(207 34 46 / 12%); }
.th-line--error { text-decoration: underline wavy #cf222e; }
.th-line--focused { opacity: 1; }
.th-code:has(.th-line--focused) .th-line:not(.th-line--focused) { opacity: 0.55; }

Use data for tooltips, diagnostics, IDs, or application hooks. Values are stringified and escaped.