Lighterhtml
The hyperHTML strength & experience without its complexity 🎉
Install / Use
/learn @WebReflection/LighterhtmlREADME
lighterhtml
<sup>Social Media Photo by Kristine Weilert on Unsplash</sup>
📣 Community Announcement
Please ask questions in the dedicated discussions repository, to help the community around this project grow ♥
The hyperHTML strength & experience without its complexity 🎉
Looking for something even smaller?
If you want 90% of functionalities offered by lightetrhtml for 2/3rd of its size, check µhtml, which is also used in "micro custom elements" µce library, hence µce-template too, plus "micro land" µland 🦄
4.2 Highlights
- the new
?boolean=${value}syntax from µhtml has landed in lighterhtml too. Feel free to read this long discussion to better understand why this syntax is better, or necessary.
faster than hyperHTML
Even if sharing 90% of hyperHTML's code, this utility removed all the not strictly necessary parts from it, including:
- no
Component, nodefineand/or intents, noconnectordisconnect, and no promises <sup><sub>(possibly in later on)</sub></sup>, everything these days can be easily handled by hooks, as example using the dom-augmentor utility - html content is never implicit, since all you have to do is to write
htmlbefore any template when you need it. However, the{html: string}is still accepted for extreme cases.
Removing these parts made the output smaller in size <sup><sub>(less than 6K)</sub></sup> but it also simplified some underlying logic.
Accordingly, lighterhtml delivers raw domdiff and domtagger performance in an optimized way.
If you don't believe it, check the DBMonster benchmark 😉
simpler than lit-html
In lit-html, the html function tag is worthless, if used without its render.
In lighterhtml though, the html.node or svg.node tag, can be used in the wild to create any, one-off, real DOM, as shown in this pen.
// lighterhtml: import the `html` tag and use it right away
import {html} from '//unpkg.com/lighterhtml?module';
// a one off, safe, runtime list 👍
const list = ['some', '<b>nasty</b>', 'list'];
document.body.appendChild(html.node`
<ul>${list.map(text => html.node`
<li>${text}</li>
`)}
</ul>
`);
Strawberry on top, when the html or svg tag is used through lighterhtml render, it automatically creates all the keyed performance you'd expect from hyperHTML wires, without needing to manually address any reference: pain point? defeated! 🍾
Available as lighterhtml-plus too!
If you are looking for Custom Elements like events out of the box, lighterhtml-plus is your next stop 👍
How to import lighterhtml/-plus
Following, the usual multi import pattern behind every project of mine:
- via global
lighterhtmlCDN utility:<script src="https://unpkg.com/lighterhtml"></script>, andconst {render, html, svg} = lighterhtml - via ESM CDN module:
import {render, html, svg} from 'https://unpkg.com/lighterhtml?module' - via ESM bundler:
import {render, html, svg} from 'lighterhtml' - via CJS module:
const {render, html, svg} = require('lighterhtml')
What's the API ? What's in the export ?
The module exports the following:
htmltag function to create any sort of HTML content when used within arendercall. It carries two extra utilities,html.for(ref[, id]), to hard-reference a specific node, andhtml.nodeto create one-off dom nodes in the wild without using therender.svgtag function to create any sort of SVG content when used within arendercall. It carries two extra utilities,svg.for(ref[, id]), to hard-reference a specific node, andsvg.nodeto create one-off dom nodes in the wild without using therender.render(node, fn|Hole)to pollute anodewith whatever is returned from thefnparameters, includinghtmlorsvgtagged layoutHoleclass for 3rd parts (internal use)
You can test live a hook example in this Code Pen.
What's different from hyperHTML ?
- the wired content is not strongly referenced as it is for
hyperHTML.wire(ref[, type:id])unless you explicitly ask for it viahtml.for(ref[, id])orsvg.for(ref[, id]), where in both cases, theiddoesn't need any colon to be unique. This creates content hard wired whenever it's needed. - the
ref=${object}attribute works same as React, you pass an object viaconst obj = useRef(null)and you'll haveobj.currenton any effect. If a callback is passed instead, the callback will receive the node right away, same way React ref does. - if the attribute name is
aria, as inaria=${object}, aria attributes are applied to the node, including theroleone. - deprecated: if the attribute name is
data, as indata=${object}, thenode.datasetgets populated with all values. - if the attribute name is
.dataset, as in.dataset=${object}, thenode.datasetgets populated with all values. - intents, hence
define, are not implemented. Most tasks can be achieved via hooks. - promises are not in neither. You can update asynchronously anything via hooks or via custom element forced updates.
- the
onconnectedandondisconnectedspecial events are available only in lighterhtml-plus. These might come back in the future but right now dom-augmentor replaces these viauseEffect(callback, []). Please note the empty array as second argument. - an array of functions will be called automatically, like functions are already called when found in the wild
- the
Componentcan be easily replaced with hooks or automatic keyed renders - if a listener is an
Arraysuch as[listener, {once: true}], the second entry of the array will be used as option.
const {render, html} = lighterhtml;
// all it takes to have components with lighterhtml
const Comp = name => html`<p>Hello ${name}!</p>`;
// for demo purpose, check in console keyed updates
// meaning you won't see a single change per second
setInterval(
greetings,
1000,
[
'Arianna',
'Luca',
'Isa'
]
);
function greetings(users) {
render(document.body, html`${users.map(Comp)}`);
}
Documentation
Excluding the already mentioned removed parts, everything else within the template literal works as described in hyperHTML documentation.
A basic example
Live on Code Pen.
import {render, html} from '//unpkg.com/lighterhtml?module';
document.body.appendChild(
// as unkeyed one-off content, right away 🎉
html.node`<strong>any</strong> one-off content!<div/>`
);
// as automatically rendered wired content 🤯
todo(document.body.lastChild);
function todo(node, items = []) {
render(node, html`
<ul>${
items.map((what, i) => html`
<li data-i=${i} onclick=${remove}> ${what} </li>`)
}</ul>
<button onclick=${add}> add </button>`);
function add() {
items.push(prompt('do'));
todo(node, items);
}
function remove(e) {
items.splice(e.currentTarget.dataset.i, 1);
todo(node, items);
}
}
What about Custom Elements ?
You got 'em, just bind render arguments once and update the element content whenever you feel like.
Compatible with the node itself, or its shadow root, either opened or closed.
const {render, html} = lighterhtml;
customElements.define('my-ce', class extends HTMLElement {
constructor() {
super();
this.state = {yup: 0, nope: 0};
this.render = render.bind(
null,
// used as target node
// it could either be the node itself
// or its shadow root, even a closed one
this.attachShadow({mode: 'closed'}),
// the update callback
this.render.bind(this)
);
// first render
this.render();
}
render() {
const {yup, nope} = this.state;
return html`
Isn't this <strong>awesome</strong>?
<hr>
<button data-key=yup onclick=${this}>yup ${yup}</button>
<button data-key=nope onclick=${this}>nope ${nope}</button>`;
}
handleEvent(event) {
this[`on${event.type}`](event);
}
onclick(event) {
event.preventDefault();
const {key} = event.currentTarget.dataset;
this.state[key]++;
this.render();
}
});
Should I ditch hyperHTML ?
Born [at the beginning of 2017](https://medium.com/@
Related Skills
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
