CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-htm

JSX-like syntax using tagged template literals for Virtual DOM without transpilation

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

core-htm.mddocs/

Core HTM API

The core HTM library provides the fundamental tagged template functionality that can be bound to any hyperscript-compatible function.

Primary API

htm.bind()

function bind<HResult>(
  h: (type: any, props: Record<string, any>, ...children: any[]) => HResult
): (strings: TemplateStringsArray, ...values: any[]) => HResult | HResult[];

Binds HTM to a hyperscript function and returns a tagged template function.

Parameters:

  • h - Hyperscript function following the pattern h(type, props, ...children)
    • type: Element type (string for HTML elements, function/class for components)
    • props: Object containing element properties/attributes, or null
    • children: Variable number of child elements

Returns:

  • Tagged template function that converts HTML-like syntax to hyperscript calls
  • Single element for one root, array for multiple roots

Usage Examples:

import htm from "htm";

// Custom hyperscript function
const h = (tag, props, ...children) => ({ tag, props, children });
const html = htm.bind(h);

// Basic element
const element = html`<div>Hello World</div>`;
// Result: { tag: 'div', props: null, children: ['Hello World'] }

// Element with props
const button = html`<button class="primary" onclick=${handleClick}>Click</button>`;
// Result: { tag: 'button', props: { class: 'primary', onclick: handleClick }, children: ['Click'] }

// Component usage
const MyComponent = ({ name }) => html`<span>Hello ${name}</span>`;
const app = html`<${MyComponent} name="Alice" />`;
// Result: { tag: MyComponent, props: { name: 'Alice' }, children: [] }

Template Syntax

Basic Elements

// Self-closing
html`<div />`
html`<img src="photo.jpg" />`

// With content
html`<div>Content here</div>`
html`<h1>Title</h1>`

// Nested elements
html`
  <div>
    <h1>Title</h1>
    <p>Paragraph</p>
  </div>
`

Dynamic Values

const className = "container";
const content = "Hello World";
const isVisible = true;

// Dynamic attributes
html`<div class=${className}>Content</div>`

// Dynamic content
html`<div>${content}</div>`

// Boolean attributes
html`<input disabled=${isVisible} />`

// Mixed static and dynamic
html`<div class="base ${className}">Content</div>`

Component Integration

const MyComponent = ({ title, children }) => html`
  <div class="component">
    <h2>${title}</h2>
    <div class="content">${children}</div>
  </div>
`;

// Component usage
html`<${MyComponent} title="Welcome">
  <p>Child content</p>
</${MyComponent}>`;

// Self-closing component
html`<${MyComponent} title="Welcome" />`;

Prop Spreading

const props = { class: "button", disabled: true };
const extraProps = { "data-test": "my-button" };

// Spread props
html`<button ...${props} onclick=${handleClick}>Click</button>`;

// Multiple spreads
html`<button ...${props} ...${extraProps}>Click</button>`;

// Mix spread and direct props
html`<button ...${props} id="special">Click</button>`;

Multiple Root Elements

// Returns array when multiple roots
const items = html`
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
`;
// Result: [{ tag: 'li', ... }, { tag: 'li', ... }, { tag: 'li', ... }]

// Fragment syntax
const fragment = html`<>
  <h1>Title</h1>
  <p>Content</p>
</>`;

Special Syntax Features

// HTML comments (ignored in output)
html`<!-- This is a comment --><div>Content</div>`;

// Implicit closing tags
html`<div>Content</>`;  // Equivalent to <div>Content</div>

// Component end tags with explicit closing
html`<${Component} prop="value">
  Child content
</${Component}>`;

Performance Features

Template Caching

HTM automatically caches compiled templates for performance:

const html = htm.bind(h);

// First call compiles and caches
const element1 = html`<div class=${class1}>Content</div>`;

// Second call with same template reuses cached version
const element2 = html`<div class=${class2}>Content</div>`;

The caching system:

  • Uses a WeakMap keyed by the hyperscript function
  • Caches compiled operation lists per template string array
  • Provides significant performance benefits for repeated template usage

Static vs Dynamic Optimization

HTM optimizes templates by distinguishing static and dynamic parts:

// Mostly static - highly optimized
html`<div class="static">Static content</div>`;

// Dynamic parts tracked separately
html`<div class=${dynamic}>Content: ${content}</div>`;

Advanced Usage

Custom Hyperscript Functions

// Virtual DOM builder
const vdom = (tag, props, ...children) => ({ tag, props, children });
const htmlVdom = htm.bind(vdom);

// HTML string builder  
const htmlString = (tag, props, ...children) => {
  const attrs = props ? Object.entries(props)
    .map(([k, v]) => ` ${k}="${v}"`).join('') : '';
  const content = children.join('');
  return `<${tag}${attrs}>${content}</${tag}>`;
};
const htmlStr = htm.bind(htmlString);

// Custom renderer with logging
const loggingH = (tag, props, ...children) => {
  console.log('Creating element:', tag, props, children);
  return { tag, props, children };
};
const htmlLog = htm.bind(loggingH);

Type Safety with TypeScript

// Define your hyperscript return type
interface VNode {
  tag: string | Function;
  props: Record<string, any> | null;
  children: any[];
}

// Type-safe hyperscript function
const h = (tag: any, props: Record<string, any> | null, ...children: any[]): VNode => ({
  tag, props, children
});

// Bind with proper typing
const html = htm.bind(h);

// TypeScript will infer VNode | VNode[] return type
const element = html`<div>Typed content</div>`;

Types

// Main HTM interface
interface HTM {
  bind<HResult>(
    h: HyperscriptFunction<HResult>
  ): TemplateFunction<HResult>;
}

// Hyperscript function type
type HyperscriptFunction<T> = (
  type: any,
  props: Record<string, any> | null,
  ...children: any[]
) => T;

// Template function type
type TemplateFunction<T> = (
  strings: TemplateStringsArray,
  ...values: any[]
) => T | T[];

// Internal caching types
interface TemplateCache extends Map<TemplateStringsArray, any> {}
interface GlobalCache extends Map<HyperscriptFunction<any>, TemplateCache> {}

docs

advanced-usage.md

core-htm.md

index.md

preact-integration.md

react-integration.md

tile.json