Microlighter
A tiny, dependency-free syntax highlighter built on the CSS Custom Highlight API and TextMate grammars.
#MicroLighter
A tiny, dependency-free syntax highlighter for the web.
MicroLighter uses the CSS Custom Highlight API and TextMate
grammars. It highlights code without adding a <span> around every token, so
your markup stays clean and editable.
#Features
- About 2 KiB compressed
- No runtime dependencies
- 37 languages, loaded on demand
- 10 bundled themes
- Clean DOM with no token markup
- Programmatic, automatic, and web component APIs
- Editable code block support
#Install
npm install microlighter
#Quick start
Add a language class to your code:
<pre><code class="language-javascript">const answer = 42;</code></pre>
Import a theme and run the highlighter:
import "microlighter/themes/github.css"; import { highlightAll } from "microlighter"; document.body.dataset.syntaxTheme = "github"; await highlightAll();
That's it. MicroLighter finds every pre > code block with a supported
language and highlights it.
#Usage
#Programmatic API
The main package exports highlightAll(). Importing it has no side effects.
import { highlightAll } from "microlighter"; await highlightAll();
Pass options to limit the scan or add project-specific language aliases:
await highlightAll({ root: document.querySelector("#docs"), selector: "pre.code > code", languageAliases: { ecmascript: "javascript", shellsession: "bash" } });
| Option | Default | Description |
|---|---|---|
root |
document |
Element or document to search |
selector |
"pre > code" |
Selector used to find code blocks |
languageAliases |
{} |
Extra aliases mapped to bundled grammars |
highlightAll() returns a promise containing the highlighted code elements.
#Automatic highlighting
Import the auto runner to highlight the page as soon as the module loads:
<link rel="stylesheet" href="./node_modules/microlighter/themes/github.css"> <script type="module" src="./node_modules/microlighter/microlighter.min.js"></script> <body data-syntax-theme="github">
After adding or changing code, dispatch this event to highlight again:
document.dispatchEvent(new Event("syntax-highlight"));
The event can also bubble from a code block or one of its parents.
#CDN
Use the auto runner directly from a CDN:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/microlighter@2/themes/github.css"> <script type="module" src="https://cdn.jsdelivr.net/npm/microlighter@2/microlighter.min.js"></script> <body data-syntax-theme="github"> <pre><code class="language-javascript">const answer = 42;</code></pre> </body>
#Web component
Import the optional <micro-lighter> custom element:
<link rel="stylesheet" href="./node_modules/microlighter/themes/github.css"> <script type="module" src="./node_modules/microlighter/micro-lighter-element.min.js"></script> <body data-syntax-theme="github"> <micro-lighter language="javascript" controls="copy" line-numbers> <pre><code>const answer = 42;</code></pre> </micro-lighter> </body>
| Attribute | Description |
|---|---|
language |
Language to use. Overrides language metadata on <pre> or <code> |
controls="copy" |
Adds a copy button |
line-numbers |
Adds a line number gutter without changing copied code |
Style the controls with ::part(copy-button) and ::part(line-numbers).
#TypeScript
Declarations ship with the package, including for the grammar and auto-run
entry points. They are generated from the JSDoc types in src/, so the source
and the published types cannot drift.
import { highlightAll, type HighlightAllOptions } from "microlighter"; import javascript from "microlighter/grammars/javascript.js";
Importing microlighter/micro-lighter-element.js also registers
<micro-lighter> in HTMLElementTagNameMap, so querySelector
returns a typed element.
#Language detection
The recommended format is a language-* class:
<pre><code class="language-typescript">const answer: number = 42;</code></pre>
You can also use data-language on <code> or <pre>:
<pre data-language="typescript"><code>const answer: number = 42;</code></pre>
Avoid <pre lang="typescript"> in new code. MicroLighter supports it for
compatibility, but the HTML lang attribute should describe human language.
Common aliases work automatically:
| Aliases | Language |
|---|---|
js, jsx |
javascript |
ts |
typescript |
sh, shell, zsh |
bash |
yml |
yaml |
md |
markdown |
sass |
scss |
docker |
dockerfile |
py |
python |
rb |
ruby |
gql |
graphql |
Custom aliases passed to highlightAll() must point to a bundled language.
#Languages
MicroLighter includes these grammars:
assembly, astro, bash, c, cpp, csharp, css, dart, dockerfile, elixir,
git-diff, go, graphql, heex, html, ini, java, javascript, json,
kotlin, lua, markdown, nginx, objective-c, perl, php, powershell,
python, r, ruby, rust, scss, sql, svelte, swift, toml, tsx,
typescript, vue, and yaml.
Grammars are ES modules and load on demand.
#Themes
Load one theme and set the matching data-syntax-theme value on <body> or
any container:
<link rel="stylesheet" href="./node_modules/microlighter/themes/night-owl.css"> <section data-syntax-theme="night-owl"> <!-- code blocks --> </section>
Bundled themes:
cobalt2draculagithubgruvboxminmonokainight-owlsolarized-lighttokyo-nightvespervscode-plus
Themes use CSS custom properties for a small color palette:
| Property | Token categories |
|---|---|
--syntax-comment |
Comments and quotes |
--syntax-keyword |
Keywords, storage, at-rules, and sections |
--syntax-operator |
Operators and punctuation |
--syntax-string |
Strings, regular expressions, links, and attribute values |
--syntax-constant |
Numbers, booleans, constants, symbols, and entities |
--syntax-function |
Functions, decorators, and animations |
--syntax-type |
Types and support tokens |
--syntax-variable |
Variables and interpolation |
--syntax-property |
Properties, keys, and attribute names |
--syntax-tag |
Tags |
--syntax-selector |
Selectors |
--syntax-inserted |
Inserted text |
--syntax-deleted |
Deleted text |
#Editable code
MicroLighter keeps code as plain text, so code blocks can remain editable. Call the highlighter after each change:
<editable-code> <pre><code class="language-javascript">const answer = 42;</code></pre> </editable-code> <script type="module"> import "microlighter/microlighter.min.js"; class EditableCode extends HTMLElement { connectedCallback() { const code = this.querySelector("pre > code"); if (!code) return; code.contentEditable = "plaintext-only"; code.spellcheck = false; code.setAttribute("aria-label", "Editable code"); this.addEventListener("input", () => { this.dispatchEvent(new Event("syntax-highlight", { bubbles: true })); }); } } customElements.define("editable-code", EditableCode); </script>
Keep <pre><code> in the light DOM so MicroLighter can find it.
#How it works
MicroLighter reads TextMate grammars with the browser's native RegExp. It
turns matching token ranges into Highlight objects and styles them with
::highlight(). It does not use Oniguruma, WebAssembly, or generated token
markup.
This keeps the library small. The trade-off is less language coverage and grammar accuracy than larger tools such as Shiki.
The low-level tokenizer is available from microlighter/highlight.js for
advanced integrations.
#Development
Requires Node.js 18 or newer.
npm install
npm run build
npm test
Useful commands:
| Command | Description |
|---|---|
npm run build |
Build dist/, update the local demo package, and report sizes |
npm test |
Build and run Node.js and Playwright tests |
npm run size |
Print the size report without changing files |
npm run docs:update-homepage-stats |
Update the homepage bundle size |
npx serve docs |
Serve the demo at http://localhost:3000 |
The build fails when the minified bundle exceeds the gzip size limit in
package.json.
See CONTRIBUTING.md for the project structure and guides for adding grammars and themes.
#Prior art
MicroLighter builds on TextMate grammars and work across the syntax highlighting community:
- Prism.js inspired the semantic CSS categories.
- Shiki is the full-featured TextMate highlighter for the web.
- Bramus Van Damme's Custom Highlight API article popularized this rendering technique.
- Related projects include textmate-highlighter, syntax-highlight-element, shiki-highlight-api, and syntaxp.
#License
MIT © Dave Rupert