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
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.
html and the internal h helper, without an intermediate HTML string..value and .disabled.onClick and onInput attached directly with addEventListener.{ current } objects.children.foreignObject content.data-* and aria-* attributes.html.html functionhtml 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.
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.
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.
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.
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>
`;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}>
`;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.
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.
h DOM adapterThe 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:
children.null or undefined) creates a DocumentFragment.Node children are appended directly, including nodes from another DOM realm.null, undefined, and booleans are skipped as children.children in the props object is ignored when explicit children are supplied to h.npm install xhtm-domThe package exposes compiled files from dist:
import: ES modulerequire: CommonJSdefault/browser: UMD buildtypes: generated TypeScript declarationsThe library expects a browser-like DOM. It is suitable for browser scripts, userscripts, and applications that already have document available.
xhtm-dom is a DOM construction utility, not a full UI framework:
html creates new DOM nodes; it does not automatically reconcile prior output.jsdom and an appropriate environment setup.For updates, keep references to created nodes or replace/modify them with standard DOM APIs.
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.
npm install
npm test
npm run buildAdditional package commands:
npm run build:types
npm run build:lib
npm run build:package
npm run dev
npm run build:docsnpm 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.
This project is licensed under the MIT License. The userscript build includes xhtm, which is also distributed under the MIT License.