Components

A page links a native HTML Next component with <link rel="component"> and uses it on the next line. Components live in app/components/, and a page links one by its path from the project root, @/:

<link rel="component" href="@/app/components/counter.html">

<demo-counter></demo-counter>
0

@/ is the project root in component links, component modules, stylesheet @imports and loader imports, as in every MarkupKit page (see Pages). The HTML Next proposal defines their syntax and behavior.

TypeScript controllers

Maintain controllers in strict ESM TypeScript, with .js references in the component's HTML, app/components/counter.html:

<link rel="component" href="@threadlabs/looma/components/ui-button/ui-button.html">
<link rel="component" href="@threadlabs/looma/components/ui-cluster/ui-cluster.html">
<template component="demo-counter" controller="./counter.js">
<defs><state name="count" type="number" value="0"></state></defs>
<ui-cluster gap="s" align="center"><ui-button data-counter-action>Increment</ui-button><output>{$count}</output></ui-cluster>
</template>
// counter.ts
import type { ComponentHost } from '@nextwebwg/html-next/runtime';

export default function counter(host: ComponentHost): void {
  host.on('connect', () => {
    const button = host.root.querySelector('[data-counter-action]')!;
    const click = () => { host.state.count = Number(host.state.count) + 1; };
    button.addEventListener('click', click);
    return () => button.removeEventListener('click', click);
  });
}

MarkupKit resolves counter.js to counter.ts in development and bundles its JavaScript for production. Vite transpiles; it does not type-check. Install TypeScript as a development dependency when importing HTML Next's controller types, and run your project's strict TypeScript check separately. Markupress maintains its controllers with TypeScript 7. Checked JSDoc is an authoring option for your own controllers.

Embeds builds a YouTube embed as a component.

Edit this page

Last updated