The Problem

Developers who embed code snippets in web pages often rely on heavyweight libraries that inject many <span> elements, bloating the DOM and breaking in‑place editing. Maintaining a large dependency tree for simple highlighting adds build‑time overhead and security surface.

What This Does

microlighter provides a dependency‑free syntax highlighter that leverages the browser’s CSS Custom Highlight API. The core runtime lives in src/microlighter.js and src/highlight.js. Language grammars are stored as separate modules under src/grammars/ (e.g., src/grammars/javascript.js, src/grammars/dockerfile.js). Themes are plain CSS files under src/themes/ (e.g., src/themes/github.css).

The public API is exported from src/index.js:

export { highlightAll } from "./microlighter.js";

highlightAll() scans the document for pre > code blocks, loads the required grammar on demand, and calls the low‑level applyHighlight() routine in src/highlight.js. No DOM mutation beyond the CSS Highlight API occurs, so the original markup stays untouched.

How It Is Wired

  1. Entry point – src/index.js re‑exports highlightAll. When a consumer imports microlighter (e.g., import { highlightAll } from "microlighter"), the module graph starts here.
  1. High‑level flow – highlightAll() (defined in src/microlighter.js) performs: Resolve the root element (document by default) and selector ("pre > code"). Iterate over each matching element, read its language class (language‑*) or data-language attribute. * Call loadGrammar(lang) which does a dynamic import() of the corresponding file in src/grammars/. The grammar objects are plain TextMate JSON structures.
  1. Core highlighting – Once a grammar is loaded, highlightAll() forwards the element and grammar to applyHighlight() in src/highlight.js. This function: Tokenizes the code using the TextMate grammar via the onigasm‑style matcher bundled in the repo. Creates a CSSHighlight range for each token type (keyword, string, comment, etc.). * Registers the ranges with the CSS Highlight API (CSS.highlights.set(name, ranges)).
  1. Theme wiring – Themes are ordinary CSS files that define ::highlight(keyword), ::highlight(string), etc. Importing a theme (e.g., import "microlighter/themes/github.css") registers those selectors globally; the API then paints the ranges created in step 3.
  1. Automatic mode – src/microlighter.js also registers a listener for the custom event syntax-highlight. When the module is loaded as a script (microlighter.min.js), it calls highlightAll() immediately, enabling the “auto runner” documented in the README.
  1. Web component – src/micro-lighter-element.js defines <micro-lighter> which internally calls highlightAll() on its shadow DOM and adds optional UI parts (copy-button, line-numbers). The component isolates its effect to its own subtree, avoiding global scans.

Call‑graph summary (key nodes)

FilePrimary Export / FunctionPrimary Consumers
src/index.jshighlightAll (re‑export)Application code, CDN bundle
src/microlighter.jshighlightAll(options)src/index.js, auto‑runner, <micro-lighter>
src/highlight.jsapplyHighlight(element, grammar)src/microlighter.js
src/grammar-dependencies.jsloadGrammar(name)src/microlighter.js
src/micro-lighter-element.jsMicroLighterElement classCustom‑element registration

No circular imports are present; the dependency direction is strictly entry → grammar loader → highlighter → CSS API. The widest blast radius is applyHighlight(), because any change there alters how all languages render.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/microlighter.git
cd microlighter

# Install dependencies (npm is declared in package.json)
npm ci

# Run the test suite (GitHub Actions uses the same command)
npm test

In‑page usage

<link rel="stylesheet" href="node_modules/microlighter/themes/github.css">
<script type="module">
  import { highlightAll } from "microlighter";
  await highlightAll();               // programmatic API
</script>

<pre><code class="language-javascript">
const answer = 42;
</code></pre>

Automatic mode (no JS import needed)

<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">
  <pre><code class="language-python">print("hi")</code></pre>
</body>

Web component

<link rel="stylesheet" href="node_modules/microlighter/themes/github.css">
<script type="module" src="node_modules/microlighter/micro-lighter-element.min.js"></script>

<micro-lighter language="rust" line-numbers controls="copy">
  <pre><code>fn main() { println!("hi"); }</code></pre>
</micro-lighter>

Real‑World Use

A static documentation site (e.g., Docusaurus) can replace a heavy Prism bundle with microlighter. Import the desired theme once, drop highlightAll() into the site’s initialization script, and all existing <pre><code> blocks become editable without DOM bloat. The component variant can be used for live‑edit sections where copy‑button and line numbers are required.

Code Health & Issues

  • Low – No structural red flags – CI workflow (.github/workflows/ci.yml) runs tests, lockfile (package-lock.json) is present, and a permissive MIT license is included.
  • Low – Test coverage limited – Only six test files exist (test/*.spec.js), covering build, grammar loading, and the custom element; deeper runtime edge cases are not exercised.
  • Low – Documentation gaps – The README stops mid‑sentence in the “Language detection” section; developers may need to infer the exact fallback rules.

No secret keys, build scripts, or undocumented environment variables were found.

The Bottom Line

microlighter delivers a truly lightweight, zero‑dependency highlighter that fits well into static sites or low‑overhead web apps. Its modular grammar loading and CSS‑only rendering keep the DOM clean, but the project’s modest test suite and incomplete README sections suggest a need for additional validation before heavy production use. Suitable for teams that prioritize bundle size and want a simple drop‑in solution.