Declarative
Web Components
in a hundred lines.
Tan Compose turns a plain JavaScript object into a real custom element — Shadow DOM, theming, lifecycle hooks, reactive state, and listener cleanup included. No framework, no compile step.
import { describe, build, html } from "@ra9/tan-compose"; build("my-counter", describe({ template: ({ state }) => html` <span>${state.count ?? 0}</span> <button class="bump">+</button> `, events: { "click .bump": (_e, ctx) => ctx.setState("count", (ctx.state.count ?? 0) + 1), }, })); // That's it. Use <my-counter> anywhere.
Tiny, predictable, browser-native.
One describe() call to define a component,
one build() call to register it. Everything
else is the platform.
~5 KB minified
Zero dependencies. Ships as a single ESM module.
Shadow DOM by default
Styles never leak. Theme via CSS custom properties on :host.
Predictable mount hooks
beforeMount / afterMount / unmount, errors caught and logged with the tag name.
Opt-in observed attrs
Declare observedAttributes and
changes re-render. No magic.
setState triggers render
Skips re-render when the value is
Object.is-equal.
Listener cleanup
Per-render cleanup queue. No leaked handlers on re-render or unmount.
From zero to a custom element.
Install with one command. Define your component as a plain object. Use it as HTML.
Install
Or import the ES module directly in your own code — pin
a tag, swap
@v1.3.0 for any release:
Define and register
Use in HTML
Each block below is a real custom element.
Built with the same library you'd
npm install. Open DevTools to inspect the
Shadow DOM.