Zero-JavaScript Syntax Highlighting with Shiki
2 min readshikiperformancemarkdown
Syntax highlighting should cost the user nothing. Shipping a highlighter to the browser means downloading a grammar engine and tokenizing every code block again, on every visit, for content that never changes after deploy.
Highlight once, at build time
The trick is to run Shiki inside the MDX compilation step. The markdown body is compiled to a string of highlighted HTML, and the client receives plain markup:
const root = highlighter.codeToHast(source, {
lang,
themes: { light: 'github-light', dark: 'github-dark' },
defaultColor: false,
})
No highlight.js, no WebAssembly grammar, no theme JavaScript. The bundle is
zero bytes heavier for the feature.
Dual themes without a re-render
Instead of baking one theme's colors into the HTML, Shiki emits CSS variables
for both palettes. Each token carries --shiki-light and --shiki-dark, and a
single rule flips them:
html.dark .shiki,
html.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
}
Switching themes is a class toggle on <html> — no re-highlight, no layout
shift.
The result is highlighted code that is instant to render and free to switch between light and dark.