v7.16.0
Features
- replace highlight.js runtime with an original highlight engine (85a0706, #461)
- compile themes to palettes with CSS-variable theming (956cf17, #463)
- expose the scope-event stream as a public API (1bfe132, #464)
- add
HighlightVirtualfor windowed rendering of huge documents (3d452e2, #466) - add
defineTheme,extendTheme, and a TextMate importer (25a6ab1, #465) - add custom
gdscriptlanguage (8aa6b1e, #471) - add custom
heexlanguage (79c4080, #471) - add custom
sparqllanguage (26e4225, #471)
Fixes
- stop
HighlightVirtual's class and sizer from leaking (588c332, #466) - scope sub-language continuation state to its own occurrence (ca0c0f5, #463)
- balance nested delimiters in string interpolation (a48a978, #470)
- recognize Vue longhand directive arguments (0d77d90, #470)
- highlight Zig function names (25da324, #470)
- highlight WGSL unsigned-integer number suffixes (a4ed905, #470)
- don't shadow Pug control-flow keywords with the tag rule (66554d1, #470)
- bound Zig fn-name match to avoid runaway scan (00b2282, #470)
- recognize Razor implicit control-flow blocks (e0e67c5, #470)
- recognize Marko concise class/id shorthand on tags (71696e4, #470)
- recognize Marko's
else-ifhyphen form (ffa164c, #470) - don't mistake email addresses for Blade directives (b239a85, #470)
- handle escaped quotes in Blade strings (efab4e9, #470)
- recognize Rego function-style rule heads (86c6df6, #470)
- fix PromQL grouping labels and subquery resolution (b41bb10, #470)
- don't mistag Nickel let-bound names as record fields (78dc9a3, #470)
- don't mistake Cypher map values for node labels (8787003, #470)
- don't tag Solidity inheritance lists as titles (972e7f1, #470)
- highlight Solidity hex literals with underscores (3e0cb72, #470)
- don't swallow a trailing hyphen into Svelte stores (63a5ee5, #470)
- highlight parameterless HLSL attributes (bd46ac0, #470)
- stop HLSL semantics matching ternary/switch colons (c4199e0, #470)
- make Typst strong/emphasis respect the whitespace rule (c5dbb00, #470)
- recognize bare Typst
#{ }code blocks (bcf10d5, #470) - balance nested braces in Templ legacy script blocks (e663d9f, #470)
- recognize Just recipe params with function-call defaults (be19bf3, #470)
- style Astro's closing frontmatter fence (88acf74, #470)
- highlight Caddy multi-address site headers (4ddfe89, #470)
- stop Nushell
def-envfrom corrupting the title match (9e50e7e, #470) - highlight compound LogQL durations (b5e9cd7, #470)
- keep MDX JSX tags open through a
>inside{...}(882f6b3, #470) - don't mistake a Prisma field named
typefor a declaration (3570394, #470)
Original highlight engine
svelte-highlight no longer ships a highlight.js runtime. Highlighting is handled by an in-package engine that consumes plain-JSON grammar IR. Everyday usage is unchanged: language imports, <Highlight language={…} {code} />, and .hljs / hljs-* class contracts still work.
highlight.js was removed from published dependencies. If you relied on it transitively, install it yourself. Custom languages that used register: (hljs) => mode should migrate to fromHighlightJs from svelte-highlight/compat (optional peer install of highlight.js), or ship converted grammar IR.
<script>
import Highlight from "svelte-highlight";
import typescript from "svelte-highlight/languages/typescript";
const code = "const add = (a: number, b: number) => a + b;";
</script>
<Highlight language={typescript} {code} />import { fromHighlightJs } from "svelte-highlight/compat";
// requires: npm i highlight.js
const language = await fromHighlightJs("custom-language", (hljs) => ({
contains: [],
}));Theme palettes with CSS variables
Every shipped theme is also a typed ThemePalette of --shl-* variables. Pair a palette with svelte-highlight/themes/base.css. Legacy svelte-highlight/styles/* strings still work. HighlightStyle accepts theme / light / dark as a string or palette.
<script>
import { Highlight, HighlightStyle } from "svelte-highlight";
import typescript from "svelte-highlight/languages/typescript";
import atomOneDark from "svelte-highlight/themes/atom-one-dark";
import "svelte-highlight/themes/base.css";
const code = "const add = (a: number, b: number) => a + b;";
</script>
<HighlightStyle theme={atomOneDark}>
<Highlight language={typescript} {code} />
</HighlightStyle>Scope-event stream API
The engine exposes a balanced scope-event stream (TEXT / OPEN / CLOSE). Components forward it as let:events and on:highlight → detail.events. For headless use, import from svelte-highlight/engine.
import { createRegistry, registerAll, tokenLines } from "svelte-highlight/engine";
import typescript from "svelte-highlight/languages/typescript";
const registry = createRegistry();
registerAll(registry, typescript);
const { events, value } = registry.highlight(code, { language: "typescript" });
const lines = tokenLines(events);<Highlight language={typescript} {code} let:highlighted let:events>
<pre><code>{@html highlighted}</code></pre>
</Highlight>HighlightVirtual for huge documents
HighlightVirtual renders only the viewport (plus overscan) for large static files — a 100k-line dump stays a couple dozen DOM line nodes. SSR emits full plain escaped text; windowed highlighting kicks in after hydration.
<script>
import { HighlightVirtual } from "svelte-highlight";
import json from "svelte-highlight/languages/json";
</script>
<HighlightVirtual language={json} code={hugeLogDump} style="height: 480px" />defineTheme, extendTheme, and TextMate import
Author palettes programmatically from semantic roles, extend an existing theme, or import a VS Code / TextMate theme JSON.
import { defineTheme, extendTheme } from "svelte-highlight/theme";
import { fromTextMate } from "svelte-highlight/theme/textmate";
import atomOneDark from "svelte-highlight/themes/atom-one-dark";
const midnight = defineTheme({
name: "midnight",
roles: {
background: "#0b1021",
foreground: "#d6deeb",
keyword: "#c792ea",
},
});
const branded = extendTheme(atomOneDark, {
name: "branded",
roles: { keyword: "#ff79c6" },
});
const palette = fromTextMate(nightOwlJson, { onWarn: console.warn });Custom gdscript, heex, and sparql languages
These grammars are maintained by svelte-highlight. Import them from svelte-highlight/languages like any other language.
The gdscript grammar highlights Godot GDScript: func / class_name / extends, typed params, @export annotations, and $NodePath / %UniqueName lookups.
The heex grammar highlights Phoenix HEEx templates: embedded Elixir (<%= %>, { }), components (<.form>), and HTML markup.
The sparql grammar highlights SPARQL queries: PREFIX, SELECT / WHERE, graph patterns, and filters.
<script>
import Highlight from "svelte-highlight";
import gdscript from "svelte-highlight/languages/gdscript";
import heex from "svelte-highlight/languages/heex";
import sparql from "svelte-highlight/languages/sparql";
const gdCode = `extends Node2D
@export var speed: float = 100.0
func _ready() -> void:
$Label.text = "Hello"`;
const heexCode = `<.form for={@changeset} phx-submit="save">
<.input field={@changeset[:email]} type="email" />
<button>Save</button>
</.form>`;
const sparqlCode = `PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name
WHERE {
?person foaf:name ?name .
}`;
</script>
<Highlight language={gdscript} code={gdCode} />
<Highlight language={heex} code={heexCode} />
<Highlight language={sparql} code={sparqlCode} />