Syntax Highlighting

Choose from four syntax highlighting engines in unifast: tree-sitter, syntect, Shiki, and highlight.js.

unifast supports four syntax highlighting engines. Two run inside the Rust compiler (tree-sitter, syntect), and two run in JavaScript (Shiki, highlight.js).

Comparison

tree-sittersyntectShikihighlight.js
RuntimeRust (built-in)Rust (built-in)JavaScriptJavaScript
ParsingAST-based (tree-sitter grammars)Regex-based (TextMate grammars)Regex-based (VS Code grammars)Regex-based (highlight.js grammars)
SpeedFastestFastSlowerSlower
Languages29 languages + syntect fallback100+ (TextMate)VS Code grammars190+
CSS outputClass-based (ts-*)Class-based (sy-*)Inline styles or class-basedClass-based (hljs)
Package@unifast/node@unifast/node@unifast/shiki@unifast/highlight
Best forPrecise highlighting, broad coverageSimple setup, fast startupFine-grained theme controlhighlight.js theme ecosystem

Using tree-sitter

tree-sitter uses AST-based parsing for precise syntax highlighting. It runs inside the Rust compiler and supports 29 languages natively. For unsupported languages, it automatically falls back to syntect.

tree-sitter is included in @unifast/node — no separate install needed.

import { compile, treeSitter } from "@unifast/node";

const result = compile(
  '```typescript\nconst x: number = 42;\n```',
  { plugins: [treeSitter()] }
);

tree-sitter generates CSS class names prefixed with ts-. You need to provide CSS rules for these classes in your stylesheet.

Supported languages

TypeScript, TSX, JavaScript, HTML, CSS, Python, Rust, JSON, YAML, Go, Ruby, TOML, Swift, PHP, Java, Lua, Scala, Zig, Elixir, OCaml, R, Make, Nix, Regex, Erlang, Bash, C, C++, CMake

Language aliases are also supported (e.g. ts, py, rs, sh, yml, rb).

Using syntect

syntect uses TextMate grammars and runs entirely inside the Rust compiler — no additional JavaScript overhead.

syntect is included in @unifast/node — no separate install needed.

import { compile, syntect } from "@unifast/node";

const result = compile(
  '```typescript\nconst x: number = 42;\n```',
  { plugins: [syntect()] }
);

syntect generates CSS class names prefixed with sy-. You need to provide CSS rules for these classes in your stylesheet.

Using Shiki

Shiki uses VS Code’s TextMate grammar engine for accurate highlighting with theme support.

import { compile } from "@unifast/node";
import { createShikiPlugin } from "@unifast/shiki";

const shiki = await createShikiPlugin({
  theme: "github-dark",
  langs: ["typescript", "rust", "bash"],
});

const result = compile(
  '```typescript\nconst x: number = 42;\n```',
  { plugins: [shiki] }
);

Using highlight.js

@unifast/highlight uses lowlight (highlight.js) and runs as a HAST transform in JavaScript. It supports 190+ languages and works with any highlight.js theme.

import { compile } from "@unifast/node";
import { highlight } from "@unifast/highlight";

const result = compile(
  '```typescript\nconst x: number = 42;\n```',
  { plugins: [highlight()] }
);

highlight.js generates class names with the hljs prefix. Use any highlight.js theme CSS for styling.

Line Numbers

All engines support line numbers. Enable them in the compile options:

import { compile, treeSitter } from "@unifast/node";

const result = compile(source, {
  plugins: [treeSitter()],
  lineNumbers: true,
});

Each line is wrapped in a <span> with a data-line attribute for CSS-based styling:

[data-line]::before {
  content: attr(data-line);
  display: inline-block;
  width: 2rem;
  text-align: right;
  margin-right: 1rem;
  color: #6b7280;
}

See Also