Skip to content

Counter: Vanilla

VanillaCounter.astro
<!-- render HTML that is going to be used by my-button -->
<my-button>
<button disabled>Clicks: 0</button>
</my-button>
<!-- load the implementation of the component -->
<script>
import "./vanilla-counter";
</script>

(source)

vanilla-counter.ts
// define a custom element
export class MyButton extends HTMLElement {
connectedCallback() {
const button = this.querySelector("button");
if (!button) throw new Error("<my-button> must contain a <button>");
button.disabled = false;
let count = 0;
button.onclick = () => {
count++;
button.textContent = `Clicks: ${count}`;
};
}
}
if (typeof customElements !== "undefined") {
if (customElements.get("my-button")) {
console.warn(
"Can't redefine custom element <my-button>. Page reload required.",
);
}
customElements.define("my-button", MyButton);
}

(source)

This example is there to contrast the implementation with the version using lift-html. Initial component markup is generated by the server, then once client side implementation of custom element is loaded then disabled attribute is removed and click handler is added to the button. See also versions using @lift-html/solid and @lift-html/core.