I made a smol client-side syntax highlighter that uses the CSS Custom Highlights API called MicroLighter. I’ll talk astir why I made it successful a spot but first I wanted to… ahem… highlight… immoderate of the features.
- Zero-dependencies
- ~2kb minifed+gzipped
- Uses CSS ::highlight(token-name), not spans
- Leverages Textmate’s connection grammars
- Human-readable light-dark() themes
- All languages/grammars loaded on-demand
- Moves each non-highlight functionality to a <micro-lighter> civilization element
At immoderate constituent I collapsed syntax highlighting connected my Jekyll blog. I’ve utilized a fistful of syntax highlighters complete the years (Highlight.js, PrismJS, Rouge, Shiki, etc, etc) and I’ve felt the trade-offs betwixt different client-side and server-side implementations. Faced pinch picking another, I knew I wanted to research Bramus’s method of syntax highlighting pinch the CSS Custom Highlights API.
There’s immoderate limitations pinch the CSS ::highlight() pseudo; nary italics, nary bold, nary font swapping – but different it’s beautiful cool syntax to idiomatically definitive “I want to item this token” via CSS alternatively of injecting spans everywhere. Using the Highlight API intends I debar immoderate DOM mutation and the scope of the room shrinks down to: scan codification blocks utilizing regex patterns and nonstop CSS.highlights.set(category, textRanges) to item the codification blocks.
I don’t request overmuch syntax highlighting connected this site. Not each posts person codification and my codification samples are a full 15 lines agelong astatine best. My struggle is that I switch languages often. I’ll do HTML, CSS, and JavaScript each successful the aforesaid post. A small bash here, a small ruby there, immoderate markdown arsenic a treat. Using truthful each those languages grew the complexity beyond the limits of my regex-fu, truthful I decided to thin connected Textmate’s established collections of patterns utilized by VS Code. And earlier I knew it, my small highlighter could do almost immoderate language.
Knowing I usage different languages often, 1 rule I established was that each connection grammars should beryllium auto-loaded on-demand to trim configuration and bundle size. That measurement you only salary for what you use.
Inspired by PrismJS’s simplified token categories I flattened down Textmate’s granular token categories to a much human-friendly set, making it easier to style. In summation to that, 1 tremendous nit-pick I person pinch codeblock styling is that ray and acheronian themes are abstracted entities, truthful I merged them into 1 taxable utilizing light-dark().
The past large sentiment I baked successful was that I wanted the syntax highlighter to do 1 job: infer connection and item codification successful that language. With that a guideline, I moved each other functionality (like line-numbers, etc) complete to a web component. The vanilla web constituent adds astir ~1 KiB successful size, but co-locating UI into a UI primitive for illustration autochthonal civilization elements feels correct and the ShadowDOM encapsulation makes it easy to abstracted the codification from the presentational UI.
Obviously, I’m a web constituent pervert but it feels for illustration a awesome separation of concerns versus trying to cram everything into halfway library.
Try it out
To get started connected your site, I’d usage the self-initializing minified bundle, but I’m besides shipping ESM and a web component.
npm instal microlighter <script type="module" src="path/to/microlighter/microlighter.min.js"></script>Like I said above, not each my posts person syntax highlighting, truthful I moreover hold to import the book unless I cognize there’s a page pinch codification connected it.
if(document.querySelector('pre>code').length) { import('path/to/microlighter/microlighter.min.js'); }You tin usage the ESM type if you’re going to do thing fancy yourself:
import { highlightAll } from 'microlighter' highlightAll({ selector: 'pre.onlyTheseGetHighlights' })And you tin besides usage the web constituent if you want those other features I talked about:
<micro-lighter data-syntax-theme="github" line-numbers controls="copy"> <pre><code>Code goes here</code></pre> </micro-lighter>Web constituent classes are beautiful extendible excessively truthful if I don’t support thing you need, you tin “fork” it by extending the guidelines people and adding your ain features.
Lastly, you tin usage 1 of the pre-supplied themes aliases rotation your own. The basal building is:
/** * Setup semantic `--syntax-*` tokens * @value inheritance | foreground | remark | keyword | * usability |string | changeless | usability | type | adaptable | * spot | tag | selector | inserted | deleted */ [data-syntax-theme="my-theme-name"] { color-scheme: ray dark; /* Code artifact tokens */ --syntax-background: light-dark(#f8f8f8, #3a3a3a); --syntax-foreground: light-dark(#3a3a3a, #f8f8f8); /* Highlight tokens */ --syntax-comment: light-dark(#6e7781, #8b949e); --syntax-function: light-dark(#8250df, #d2a8ff); /* ...etc... */ } [data-syntax-theme="my-theme-name"] pre:has(code) { background-color:var(--syntax-background); color:var(--syntax-foreground) } ::highlight(comment) { color: var(--syntax-comment) } ::highlight(function) { color: var(--syntax-function) } /* ...etc... */And that’s MicroLighter. If you extremity up utilizing it and trying it out, fto maine cognize what you think.
English (US) ·
Indonesian (ID) ·