Web components in ClojureScript started as an experiment born from frustration with a client stack of re-frame, React and many supporting libraries. Web components promise encapsulation and smaller bundles, but their API is complex and they leave rendering to you.
What is a web component
A web component is a custom HTML element. Once it is registered, the browser treats it like a native element.
It rests on three standards: custom elements, shadow DOM for private styling, and templates for internal structure. A bento grid built from custom tags shows how they fit together.
What does an implementation have to cover
A component has to handle identity, inputs, rendering, lifecycle, encapsulation, slots, outputs, styling, accessibility and form behaviour.
Each of these is a responsibility for the author of the component. None of them comes for free.
Writing a Web Component in CLJS
The approach follows the design choices of BareDOM, so it is opinionated. A decorative animated component, x-gaussian-blur, shows what a web component can do.
Let's start writing a Web Component in Clojurescript
The tutorial builds x-icon, a small component that wraps an SVG and exposes theming options.
Step 1: start with data
The model file defines the tag name, the observed attributes, and the public property, event and method APIs. Parsers fall back to defaults on bad input, and a normalise function turns raw attributes into a clean view model.
The DOM file then sets up the shadow root, runs a read, check and apply render pipeline, and wires the lifecycle callbacks.
Web components are not that simple
Forms and buttons add complexity, but the process stays the same. Shared code in BareDOM is reused across components.
What do you get for it?
The icon component adds about 2 KB to a bundle.
It depends on no framework, so it works in plain JavaScript and in Angular, React, Solid, Svelte and Vue.
What isn't covered here
Server-side state, efficient re-rendering and debugging are left for a follow-up post.
Source code
BareDOM holds more than 100 web components. The source and a demo are on GitHub.