Marko
A custom element built with elements-kit is just class extends HTMLElement registered via customElements.define. Marko renders it fine at runtime — custom elements with a hyphen in the tag name are passed through as-is. TypeScript support for Marko template types is provided by @marko/language-tools and is evolving; the most reliable typing surface today is HTMLElementTagNameMap for DOM queries.
// shared element — built once, used anywhereimport { defineElement } from "elements-kit/custom-elements";import { reactive } from "elements-kit/signals";
export class XCounter extends HTMLElement { @reactive() count = 0;}
defineElement("x-counter", XCounter);Source the prop shape from the class
Two helpers exported from elements-kit/jsx-runtime:
| Helper | Shape | Use when |
|---|---|---|
InstanceProps<I> | Public instance fields only (drops the HTMLElement surface) | Annotating setters, wrapper props, or helper functions |
ElementProps<C> | Full elements-kit JSX surface — attrs, fields, events from static events, slots from [SLOTS], children | When you need the full declared surface |
Use the element in a template
Import the element registration before the template renders client-side. In a Marko component, put the import in <script> or the component’s class body:
import "./x-counter"; // registers the custom element
<x-counter count=5 />Typed document.querySelector and createElement
Augmenting the global HTMLElementTagNameMap gives you typed DOM lookups in any TypeScript file — Marko template logic, server routes, or client scripts:
import type { XCounter } from "./src/x-counter";
declare global { interface HTMLElementTagNameMap { "x-counter": XCounter; }}Make sure this file is covered by your tsconfig.json’s include array.
const el = document.querySelector("x-counter"); // XCounter | nullInstanceProps<XCounter> is useful as a type annotation when writing helper functions that operate on the element:
import type { InstanceProps } from "elements-kit/jsx-runtime";import { XCounter } from "./x-counter";
function applyProps(el: XCounter, props: InstanceProps<XCounter>) { Object.assign(el, props);}