There’s a New Custom Element Superclass on the Block
It’s always a good day when I learn about a new library to aid in authoring web components. And this time around, I got a tip in my inbox ([email protected]) all about a new kid on the block, Reactive Mastro.
Mastro itself is a MPA-oriented JavaScript web framework currently in the works by Mauro Bieg, and the client-side reactivity part of it is what we’re looking at here. It’s very small (2.6kB), especially when considering that includes the signals library which Reactive Mastro is dependent on, @maverick-js/signals, and it provides a clear path to writing custom elements which are primarily driven by server-rendered HTML but need some additional interactivity after the fact.
Here’s a typical counter example provided by Reactive Mastro:
<my-counter>
Count is <span data-bind="count">0</span>
<button data-onclick="inc">+</button>
</my-counter>
import { ReactiveElement, signal } from "mastro/reactive"
customElements.define("my-counter", class extends ReactiveElement {
count = signal(0)
inc () {
this.count.set(c => c + 1)
}
})
I created a larger CodePen demo to show some of these features in action: wiring up event handlers, binding DOM elements to signal values, reacting to signal mutations in custom effects, etc. The syntax is easy to learn and rather elegant, and it reminds me of my past days working with HTML containing bindings to Knockout or Vue models.
The one knock I have against Reactive Mastro: no support currently for shadow DOM, only content in light DOM. I filed an issue here if you’re interested in tracking it.
Nevertheless, I think this is a library worth checking out! It might be the fastest route to experimenting with signal-based reactivity. As the author puts it:
Reactive Mastro sits somewhere in between React/Vue/Solid/Svelte one one end, and Alpine/HTMX/Stimulus on the other end – while being smaller and simpler than all of them. It’s a thin wrapper around “HTML Web Components” and signals, and it can be used with any static site or server returning HTML.