Skip to content

API reference

The complete reference for @johnhenry/html-modules, checked against the source (src/) and the tests (test/). The guide pages are the guided tour; this is the lookup table. It is split into pages:

Page Covers
HTML syntax Every element and attribute an HTML module or a page can write: <html-export>, <html-import>, <html-binding>, <html-import-settings>, <html-module-settings>. Placement rules, option precedence, and what each validation error says.
Elements (DOM API) The properties, methods, states and events of the elements once @johnhenry/html-modules/browser has defined them: .module, .ready, .load(), .state, .elements, .bindings, .tags, .settings, .delimiter, and the load / error event detail shapes.
JavaScript API: HTMLModules createHTMLModules() and its options, the instance (load, import, bind, resolve, cache, options, base, delimiter, loader), the lazy-loading handle, defineHTMLModuleElements(), and the lower-level loader (createLoader, linkHTMLModule, createNamespace) and lazy-loading primitives (lazyTargets, watchLazy, componentRoot).
Runtime: definitions and binding HTMLComponent / defineHTMLComponent, HTMLStylesheet / defineHTMLStylesheet, registration (defineElement, toComponent), binding (bindModule, applyBinding, registerComponents), and the helpers compiled output uses (manifest, namespaceComponents, lookupExport, componentsOf, adoptStylesheet, the is* predicates).
Module records and settings The module record JSON shape, readHTMLModule / scanHTMLModule / recordFromRaw / moduleImportOptions, and the settings vocabulary (IMPORT_DEFAULTS, EXPORT_DEFAULTS, readImportSettings, readModuleSettings, readImportOptions, resolveImportOptions).
Names DELIMITER, bindingName, parseBindingName, isValidDelimiter, isValidElementName, elementNameProblem, isKebabName, camelCase, kebabCase: the naming rules for exports, namespaces, delimiters and tags.
Compiler and CLI compileHTMLModule, compileRecord, rewriteSpecifier, rebaseSpecifier, the html-module CLI and its flags, and the esm and register output formats with a full generated example.
Dev server, hot reload and Vite html-module dev [dir] (static server, file watching, hot reload over SSE), HTMLModules.hotReload(), what hot replacement swaps and what makes the page reload, the @johnhenry/html-modules/vite plugin and createDevServer().
Sanitizing templates The opt-in sanitize option for modules from less-trusted origins: its signature and context, where it can be set (instance, import, element property), why it runs at load time, what it covers (and refuses: JavaScript imports), reports as events, caching, and the @johnhenry/html-modules/safe-fragment adapter with a table of what a template loses under each safe-fragment profile.
Errors Every error the library raises: its type, its message, and where it is reported (thrown, a rejection, or an error event on which element).

The package is plain ES modules with no runtime dependencies (@johnhenry/safe-fragment is an optional peer of /safe-fragment only). package.json exports:

Specifier File What it is
@johnhenry/html-modules src/index.js Everything below except the browser bootstrap. Side-effect free: importing it defines no elements and registers nothing.
@johnhenry/html-modules/browser src/browser.js The one-script bootstrap. Has side effects: creates the shared instance HTMLModules (bare specifiers resolved with import.meta.resolve, so through the page’s import map), defines the five elements on customElements, and sets globalThis.HTMLModules if it is not already set. Exports HTMLModules, HTMLImport, HTMLBinding, HTMLExport, HTMLImportSettings, HTMLModuleSettings.
@johnhenry/html-modules/runtime src/runtime.js Only the runtime: what compiled modules import. Exports HTMLComponent, HTMLStylesheet, defineHTMLComponent, defineHTMLStylesheet, isHTMLComponent, isHTMLStylesheet, isStylesheet, isElementLike, toComponent, defineElement, adoptStylesheet, lookupExport, componentsOf, applyBinding, bindModule, registerComponents, manifest, namespaceComponents, configureRuntime, renderDeclarative, unadoptStylesheet, hotReplaceComponent, hotReplaceStylesheet, hotReplaceModule, supportsScopedRegistries.
@johnhenry/html-modules/compiler src/compiler.js compileHTMLModule, compileRecord, rewriteSpecifier, rebaseSpecifier. Runs anywhere (Node, a dev server, a browser): no DOM needed.
@johnhenry/html-modules/dev src/dev-server.js createDevServer() and injectClient(): the server behind html-module dev. Node only.
@johnhenry/html-modules/vite src/vite.js The Vite plugin (default export). Node only.
@johnhenry/html-modules/safe-fragment src/safe-fragment.js safeFragmentSanitizer() and registerTemplateProfile(): an adapter from @johnhenry/safe-fragment to the sanitize option. It does not depend on safe-fragment (an optional peer you pass in or let it import()); see Sanitizing templates.
@johnhenry/html-modules/package.json package.json For tools that read the version.

The bin is html-module (bin/html-module.js); see Compiler and CLI.

The root entry point exports exactly these 56 names (npm run check prints the count):

DELIMITER EXPORT_DEFAULTS HTMLComponent HTMLStylesheet IMPORT_DEFAULTS adoptStylesheet applyBinding bindModule
bindingName camelCase compileHTMLModule compileRecord componentRoot componentsOf configureRuntime createHTMLModules createLoader
createNamespace defineElement defineHTMLComponent defineHTMLModuleElements defineHTMLStylesheet elementNameProblem
hotReplaceComponent hotReplaceModule hotReplaceStylesheet isElementLike isHTMLComponent isHTMLStylesheet isKebabName isStylesheet isValidDelimiter isValidElementName
kebabCase lazyTargets linkHTMLModule lookupExport manifest moduleImportOptions namespaceComponents parseBindingName
readHTMLModule readImportOptions readImportSettings readModuleSettings rebaseSpecifier recordFromRaw
registerComponents renderDeclarative resolveImportOptions rewriteSpecifier scanHTMLModule supportsScopedRegistries toComponent
unadoptStylesheet watchLazy

Everything else in src/ (for example assertDelimiter, bindingRecord, scanRawElements, reportLoudly, componentRootCreated) is internal: not exported from any entry point, and not reachable through exports.

Every entry point ships declarations (types/, generated from the JSDoc in src/ by npm run types, and exposed through a "types" condition in each exports entry): the record types (ModuleRecord, ImportRecord, ExportRecord, BindingRecord), ModuleNamespace, the HTMLModulesInstance returned by createHTMLModules(), Sanitizer (the sanitize option), the element classes (HTMLImportElement, …), ComponentSpec, CompileOptions and the option and result types of the API. The root, /browser, /runtime and /compiler re-export the types they use, so import type { ModuleRecord } from '@johnhenry/html-modules' works; /dev and /vite are typed too (/vite refers to Vite’s own Plugin type). tsc --noEmit over a strict typed consumer of every entry point (test/types/usage.ts) runs in npm test and in CI, and test/types.test.js fails when types/ is stale (run npm run types).

import { scanHTMLModule, type ModuleRecord, type ExportRecord } from '@johnhenry/html-modules';
import { HTMLModules, type HTMLImportElement } from '@johnhenry/html-modules/browser';
const record: ModuleRecord = scanHTMLModule(source, 'ui.html');
const ui = await HTMLModules.load('./ui.html'); // ModuleNamespace
const imp = document.querySelector('html-import') as HTMLImportElement;
const { tags } = await imp.ready;
  • Kebab name: lower-case ASCII words of letters and digits, each starting with a letter, joined by single hyphens: card, fancy-button, v2-card. Export names and namespaces are kebab names.
  • Tag: a custom element name, <namespace><delimiter><export> for a namespace import (ui--card).
  • Namespace (the module namespace object): what HTMLModules.load() resolves to, and what a compiled module’s import * as gives: camelCase named exports, components, and default when there is one.
  • Definition: an HTMLComponent, the module-local identity and rendering of a component; registered under any number of tags.
  • Defaults are written = value in signatures. “Throws” means synchronously; “rejects” means the returned promise.