htm

raw JSON →
3.1.1 verified Fri May 01 auth: no javascript

HTM (Hyperscript Tagged Markup) is a small JSX-like syntax for virtual DOM using standard JavaScript tagged templates, eliminating the need for a transpiler. Current stable version is 3.1.1, released with TypeScript module support improvements and package exports for Node 12+. It is actively maintained by the Preact team with a regular release cadence. HTM works in all modern browsers and is <600 bytes min+gzip. Key differentiators: no build step required, optional HTML-style quotes, component end-tags, HTML comments, and static subtree caching in v3. It provides off-the-shelf bindings for React and Preact, and can be customized with any hyperscript function. The package ships TypeScript type definitions, supports ESM and CJS, and can be compiled away with babel-plugin-htm for zero runtime cost in production.

error TypeError: htm is not a function
cause Using default import from 'htm' but htm returns a factory function that must be bound to a hyperscript function.
fix
const html = htm.bind(React.createElement);
error Uncaught SyntaxError: The requested module 'https://unpkg.com/htm?module' does not provide an export named 'html'
cause Trying to import { html } from the base 'htm' package, but 'html' is only available from 'htm/preact' or 'htm/react'.
fix
Use import htm from 'https://unpkg.com/htm?module' and then const html = htm.bind(React.createElement); or import { html } from 'https://unpkg.com/htm/preact?module'.
error Error: [htm] Could not find module 'preact'
cause Using htm/preact without preact installed or available in the module graph.
fix
Install preact: npm install preact
error Warning: Each child in a list should have a unique 'key' prop.
cause HTM does not automatically add key props when rendering arrays. JSX-style key attribute is required.
fix
Add a key attribute to list items: <li key=${item.id}>${item.name}</li>
breaking In v3.0.0, static subtree caching was introduced, which may cause components with side effects in static children not to be re-rendered.
fix Ensure static subtrees (no dynamic values) have no side effects in render functions. If side effects are needed, add a dynamic value (e.g., a prop) to force re-evaluation.
breaking HTM v3 dropped support for CommonJS require() in favor of ESM-only exports.
fix Use ES module import syntax (import) instead of require(). If a CommonJS environment is required, use a bundler like Webpack or Rollup, or downgrade to v2.
deprecated The htm/preact/standalone.module.js file is deprecated in favor of htm/preact/standalone (ESM) since v3.1.0.
fix Use import { html, render } from 'htm/preact/standalone' instead of the .module.js path.
gotcha Spread operators for props must use triple dots: <div ...${props}>, not <div {...props}> which is JSX-only.
fix Use ...${props} for spreading props. For boolean attributes, just include the attribute name: <div hidden>.
breaking HTM v2 removed support for mixed static and dynamic property values that was later re-added in v2.2.0. If upgrading from v1, ensure property concatenation works as expected.
fix Upgrade to htm >=2.2.0 or use a transpiler like babel-plugin-htm for consistent behavior.
npm install htm
yarn add htm
pnpm add htm

Shows how to use htm via CDN with Preact to create and render a component with dynamic content.

import { render } from 'https://unpkg.com/preact@latest?module';
import htm from 'https://unpkg.com/htm@latest?module';

const html = htm.bind(render);

const App = () => html`
  <div class="app">
    <h1>Hello, world!</h1>
    <p>This is completely ${'dynamic'}.</p>
  </div>
`;

render(html`<${App} />`, document.body);