Back
Migrating our DOM to Zig
Karl Seguin Software Engineer IconGithub
zig architecture dom performance v8 Thursday, January 8, 2026
We replaced LibDOM with our own Zig-based DOM implementation. The original design created friction between V8, our Zig layer, and LibDOM, especially around events, Custom Elements, and ShadowDOM. After six months of spare-time prototyping, we built zigdom: a leaner, more cohesive DOM that gives us full control over memory, events, and future enhancements. We also swapped in html5ever for parsing and added V8 snapshots to cut startup time. There are single-digit % performance gains, but the real win is a unified codebase that’s easier to extend.
Why We Replaced LibDOM
At a high level, the Lightpanda codebase can be described as a Zig layer sitting between V8 and LibDOM. When JavaScript is executed, like document.getElementById('spice') , V8 calls into the Zig layer which then forwards the request to the underlying LibDOM document object and then forwards the result back to V8. By using LibDOM, we gained a robust and fairly comprehensive DOM implementation with minimal effort.
However, as we worked to increase compatibility with websites in the wild, we felt ever-increasing friction between our three layers. One example is the event system baked into LibDOM. This proved awkward to expand beyond DOM-based events (e.g. input events) or even just bubbling DOM events to our Zig-based Window implementation. Another larger challenge, was integrating support for Custom Elements and ShadowDOM, written in Zig, with LibDOM. Finally, there was some concern about the lack of cohesion with respect to things like memory management and how that would impact potential future changes, like better multi-threading support.
If we were to restart the integration from scratch, knowing what we know now, we’d probably be able to avoid most of the friction we’re currently seeing. While we do modify LibDOM as needed, one approach would be to integrate V8 and LibDOM directly, applying fixes and additions directly to LibDOM. But as we wrote before, we’re fans of Zig so the discussions and prototypes we built always leaned towards replacing LibDOM with a custom Zig implementation.
zigdom
... continue reading