xhtm-dom

A tiny, framework-free DOM helper for writing HTML-like templates in plain JavaScript or TypeScript

ეს სკრიპტი არ უნდა იყოს პირდაპირ დაინსტალირებული. ეს ბიბლიოთეკაა, სხვა სკრიპტებისთვის უნდა ჩართეთ მეტა-დირექტივაში // @require https://update.greasyfork.org/scripts/591770/1909822/xhtm-dom.js.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

ავტორი
Paesss
ვერსია
1.8.0
შექმნილია
17.08.2026
განახლებულია
22.08.2026
Size
11,4 KB
ლიცენზია
MIT

xhtm-dom

A tiny, framework-free DOM helper for writing HTML-like templates in plain JavaScript or TypeScript.

xhtm-dom combines the xhtm tagged-template parser with a native DOM adapter. It creates real browser Element, SVGElement, DocumentFragment, and Text nodes without a virtual DOM, JSX compiler, or rendering runtime.

Features

  • Real DOM node creation through html and the internal h helper, without an intermediate HTML string.
  • Direct DOM property bindings with a leading dot, such as .value and .disabled.
  • Event listeners such as onClick and onInput attached directly with addEventListener.
  • Refs as callback functions or { current } objects.
  • Function components with props and children.
  • Interpolated DOM nodes, children, and recursively flattened arrays.
  • HTML and SVG element creation, including mixed foreignObject content.
  • Object and string styles, plus data-* and aria-* attributes.
  • HTML-like tagged templates with html.
  • Fragments for returning multiple top-level nodes.
  • TypeScript types for DOM props, events, refs, styles, children, and components.
  • ES module, CommonJS, and UMD library builds.

The html function

html is a tagged-template function:

html`<div>Hello</div>`

Its signature is:

function html(
  statics: TemplateStringsArray,
  ...args: unknown[]
): Node;

Use it by placing JavaScript expressions inside ${...}. The template is parsed once by xhtm, then dynamic values are supplied to the DOM adapter.

Interpolated values are handled as DOM values rather than being treated as a second HTML source. Build structure with template markup or DOM nodes instead of concatenating untrusted strings into markup.

Quick start

import html from "xhtm-dom";

const name = "Ada";

function onClick() {
  alert(`Hello, ${name}!`)
}

const button = html`
  <button class="greeting" onClick=${onClick}>
    Hello, ${name}
  </button>
`;

document.body.append(button);

html returns a Node, so its result can be passed directly to append, appendChild, or other DOM APIs.

const content = html`
  <h1>Dashboard</h1>
  <p>Ready.</p>
`;

document.querySelector("main")?.append(content);

When a template contains multiple top-level nodes, the result is a DocumentFragment. A scalar result is normalized to a Text node.

Dynamic attributes

Expressions can provide attribute values:

const link = "https://example.com";
const label = "Open example";

const view = html`
  <a href=${link} aria-label=${label}>
    ${label}
  </a>
`;

Boolean values are useful for HTML boolean attributes:

const isDisabled = true;
const view = html`
  <button disabled=${isDisabled}>
    Save
  </button>
`;

className and htmlFor are accepted by the DOM adapter and become the HTML attributes class and for when used through h or through template props.

Dynamic children and arrays

DOM nodes, nested arrays, strings, numbers, and components can be used as children. Arrays are flattened recursively.

const items = ["One", "Two", "Three"];
const list = html`
  <ul>
    ${items.map((item) => html`<li>${item}</li>`)}
  </ul>
`;

The result of each nested html call is a node and can be inserted into another template. A DocumentFragment is consumed when it is appended, following normal DOM behavior.

Styles, data, and ARIA attributes

Use a CSS string or an object for style:

const css = { color: "rebeccapurple", padding: "1rem" };

const view = html`
  <div style=${css}>
    Styled content
  </div>
`;

The dataset helper converts camelCase keys to data-* attributes:

const dataset = { userId: 42, source: "inbox" };

const view = html`
  <div dataset=${dataset}>
    Message
  </div>
`;

data-* and aria-* attributes can also be written directly in markup:

const view = html`
  <button data-action="save" aria-label="Save document">
    Save
  </button>
`;

Components

A component is a function that receives props and optional children, then returns a DOM node, fragment, text, or an array of supported children.

const Card = ({ title, children }) =>
  html`
    <article class="card">
      <h2>${title}</h2>
      ${children}
    </article>
  `;

const view = html`
  <${Card} title="View">
    <p>This is the card content.</p>
  </${Card}>
`;

DOM properties, events, and refs

The adapter uses attributes by default. Prefix a prop with . to assign the corresponding DOM property directly:

const input = html`
  <input value="initial" .value=${"live value"} .disabled=${false} />
`;

This distinction matters for live form state: value="..." sets an attribute, while .value=${...} sets the current HTMLInputElement.value property.

Event props beginning with on are registered with addEventListener. Common handlers are typed, including onClick, onInput, onChange, and onKeydown:

const view = html`
  <button onClick=${(event: MouseEvent) => {
    console.log(event.currentTarget);
  }}>
    Click
  </button>
`;

A ref can be a callback or a mutable object:

const inputRef = { current: null as HTMLInputElement | null };

const view = html`
  <input ref=${inputRef} />
`;

inputRef.current?.focus();

Refs are assigned while the element is created. This library does not manage ref cleanup or component lifecycles.

Self-closing and optional-close tags

XHTM accepts useful HTML shorthand:

const controls = html`
  <input type="search" />
  <br />
`;

const paragraphs = html`<p>First<p>Second`;

It also supports normal HTML directives such as <!doctype html> where the target DOM accepts them.

For reusable logic that needs typed props, a function component is usually clearer than a dynamic tag name.

The h DOM adapter

The lower-level helper has the shape:

h(tag, props?, ...children)

Examples:

const button = h("button", {
  class: "primary",
  disabled: false,
  onClick: () => console.log("saved"),
}, "Save");

const fragment = h(null, null,
  h("span", null, "First"),
  h("span", null, "Second"),
);

Behavior includes:

  • A string tag creates an HTML element, or a recognized SVG element in the SVG namespace.
  • A function tag calls the function with copied props and normalized children.
  • A missing tag (null or undefined) creates a DocumentFragment.
  • Node children are appended directly, including nodes from another DOM realm.
  • Strings and numbers become text nodes.
  • null, undefined, and booleans are skipped as children.
  • children in the props object is ignored when explicit children are supplied to h.

Installation

npm install xhtm-dom

The package exposes compiled files from dist:

  • import: ES module
  • require: CommonJS
  • default/browser: UMD build
  • types: generated TypeScript declarations

The library expects a browser-like DOM. It is suitable for browser scripts, userscripts, and applications that already have document available.

What this library does not do

xhtm-dom is a DOM construction utility, not a full UI framework:

  • It does not diff or update an existing tree.
  • It does not provide state management, effects, routing, or lifecycle hooks.
  • Calling html creates new DOM nodes; it does not automatically reconcile prior output.
  • Event listeners are attached directly to the created elements.
  • Server-side rendering requires a DOM implementation such as jsdom and an appropriate environment setup.

For updates, keep references to created nodes or replace/modify them with standard DOM APIs.

Userscript build

The Vite userscript entry point assigns the function to globalThis.html:

const view = html`<div class="notice">Loaded</div>`;
document.body.append(view);

The generated userscript bundles xhtm and can be used in a browser userscript manager. The current Vite match configuration targets all HTTP and HTTPS pages; adjust the userscript metadata before publishing a narrower script.

Development

npm install
npm test
npm run build

Additional package commands:

npm run build:types
npm run build:lib
npm run build:package
npm run dev
npm run build:docs

npm run build:docs reads this README and writes a filled GitHub copy to README.md plus a fully rendered HTML copy to docs/README.greasyfork.md. It expands package metadata, converts Markdown to HTML, and renders fenced code blocks with Shiki. Run it again whenever the source README changes before publishing.

This source file uses Handlebars' Mustache-style templates. Package metadata is available under package, so xhtm-dom and 0.0.0 are replaced from package.json during the build.

License

This project is licensed under the MIT License. The userscript build includes xhtm, which is also distributed under the MIT License.