microlighter
v2.1.0
Published
A tiny, dependency-free syntax highlighter built on the CSS Custom Highlight API and TextMate grammars.
Downloads
1,054
Maintainers
Readme
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
- 35 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 microlighterQuick 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).
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, bash, c, cpp, csharp, css, dart, dockerfile, elixir,
git-diff, go, graphql, heex, html, java, javascript, json,
kotlin, lua, markdown, 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:
cobalt2draculagithubminmonokainight-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 testUseful 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
