JavaScript

← All sections · part of the machine-readable /all/ index.

JavaScript

JavaScript

JavaScript runs in two places on Pagelove, and this section is split to match:

The rest of this page is the client library. For the server side, see Server-side JavaScript below.

Loading the library (client)

Most pages need only two script tags:

<script type="module" src="https://pagelove.github.io/beta-js/pagelove/sse.mjs"></script>
<script type="module" src="https://pagelove.github.io/beta-js/pagelove.mjs"></script>

Loading pagelove.mjs auto-instantiates a Pagelove instance bound to <main> when the page has one, so most pages need no application JavaScript. See The Pagelove class for auto-start details and how to construct instances explicitly.

The five files

File Purpose
pagelove.mjs Main entry point. Discovers schema instances and templates in HTML, renders views, binds changes bidirectionally, and routes declarative commands.
pagelove/component.mjs Base class for custom elements. Provides PageloveComponent, default binders, mixin registry, and built-in Draggable/Resizable/Stackable mixins.
pagelove/primitives.mjs Low-level HTTP client. PLDocument and PLElement handle range-addressed requests and selector generation. Used internally by pagelove.mjs.
pagelove/sse.mjs Server-Sent Events mutation streamer. Opens an event stream on import and feeds mutations into the view.
pagelove/debug.mjs Bitwise debug channels for module-level logging. Gated by a bitmask applied at import time.

What's documented on each page

HTML patterns you write:

JavaScript API:

Real-time:

Lower layer:

Utility:

Server-side JavaScript

The same language authors server-side schema logic, evaluated by dombase-js during composition and validation:

Composition-time JavaScript expression bindings (j: attributes) also run server-side; they live with the other page-composition bindings under Composing pages.

See also

Schema instances in HTML

Schema instances in HTML

A schema instance is an HTML element marked up with Microdata that pagelove.mjs recognizes as an addressable record.

When to reach for it

Reach for an instance whenever a record needs to live on the page. Use one per note, post, comment, or any other typed item the renderer will bind to a template and the patch pipeline will mutate in place.

Anatomy of an instance

An instance is an <article> element carrying Microdata attributes. The element's tag does not have to be <article>, but create() always produces one.

Attribute Required Purpose
itemscope yes Marks the element as a Microdata item.
itemtype yes Names the schema URL. Must match a registered template.
id only if the instance will be edited, deleted, or bound Routing key for patches and view binding.

Instances created by create() receive an auto-generated id of the form item-<base36-timestamp><random>.

How instances are discovered

On load, pagelove.mjs runs #discoverInstances() against the document. The selector is:

[itemscope][itemtype]:not(template):not([itemprop])

Discovery rules:

The renderer locates a template by exact itemtype URL match against <template itemtype="…"> elements already indexed by #discoverTemplates().

Property elements inside an instance

create() builds one child element per property, keyed off the schema type:

Property type Element shape
Text, Integer, Number, Boolean <meta itemprop="…" content="…">
Date, DateTime <time itemprop="…" datetime="…">
Nested schema type A child <article itemscope itemtype="…">

Properties with cardinality 0..n and no value are omitted at creation and appended later. Nested schema values must be passed as an HTMLElement; raw objects are skipped.

The full grammar of property elements lives on the sibling page Schema definitions in HTML.

Examples

Primitive properties only

<article itemscope
         itemtype="https://schema.host/Note"
         id="item-lxk3p2m1-a7b4">
  <meta itemprop="title" content="Grocery list">
  <meta itemprop="body" content="Bread, olives, lemons.">
  <meta itemprop="color" content="#ffd166">
</article>

Nested item

<article itemscope
         itemtype="https://schema.host/Post"
         id="item-lxk3p9zq-f2c8">
  <meta itemprop="title" content="On discovery">
  <time itemprop="publishedAt" datetime="2026-04-08T09:15:00Z"></time>
  <article itemprop="author"
           itemscope
           itemtype="https://schema.host/Person"
           id="item-lxk3pa11-91de">
    <meta itemprop="name" content="Ada Park">
    <meta itemprop="handle" content="ada">
  </article>
</article>

The nested <article> carries both itemprop="author" (tying it to the parent) and its own itemscope/itemtype. Because it has itemprop, #discoverInstances() will not treat it as a top-level instance — it belongs to its parent.

See also

JavaScript in schemas

JavaScript in schemas

JavaScript in schemas lets you embed ES module source in a property's default, @read, @write, @validate, or @computed, and in a Method's implementation. The server evaluates the module on every write or read in an isolated context, sharing the request budget with Sessel. The same source is also browser-runnable, so a binding may also execute client-side under the future browser-side schema runtime.

When to reach for it

Reach for a JavaScript binding when the logic is more naturally expressed as a small ES module than a Sessel expression — for example, when reusing a familiar JavaScript idiom for string normalisation, when the same source needs to run unchanged on the server and (later) in the browser, or when the binding needs to construct schema instances via the pagelove:schema import.

JavaScript authors the default slot, the three pipeline slots (@read, @write, @validate), the schema-level @validate slot, computed properties (@computed), and method bodies (implementation). Other expression slots accept Sessel only at present: constraints, mutation handlers, HTTP queries, and e:-attribute expression bindings in SSPI templates. Group constraints and shape constraints are not expressions in either language — they are declarative Microdata and CSS selector forms.

Shape

A JavaScript binding is a typed Microdata item with itemtype="https://pagelove.org/JavaScript/Module" placed in a property's default, @read, @write, or @validate slot. Its source child carries the ES module text, conventionally inside a <script type="module"> so the same string is also browser-runnable.

<div itemprop="default" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default () => String(Math.floor(100 + Math.random() * 500));
  </script>
</div>

The dispatcher selects the language by the itemtype URL of the typed item, never by <script type>. The <script> tag is a browser-execution affordance, not a server-data signal.

The export default contract

The module must have a default export, and that export must be a function — arrow or function form. The server:

  1. Evaluates the module in a fresh context.
  2. Reads the default export off the module namespace.
  3. Verifies it is a function.
  4. Calls it with this bound to the in-progress instance and one positional argument, context.
  5. Converts the return value back to a dombase value.

ES modules always run in strict mode, so arrow functions do not bind their own this. A binding that needs to read this must use a function form:

export default function() { return this.firstname; }

A module with no default export, or a default export that is not a function, fails with the shape variant.

Slot semantics

Slot First argument / this Return value When it fires
default this is the in-progress instance; first positional argument is context The default value to inject when the property is absent At write time, before validation
@read First argument is the property value flowing through the chain The transformed value, passed to the next stage After fetch from storage, before the response is sent
@write First argument is the property value flowing through the chain The transformed value, passed to the next stage Before validation, before storage
@validate (property-level) First argument is the property's current value after defaults Truthy to accept; falsy or thrown to reject At persistence (PUT), after defaults, before the required-property check
@validate (schema-level) this is the serialized instance (an element HTML string); the positional context argument is null for this slot Truthy to accept; falsy or thrown to reject At persistence (PUT), after cardinality, type, property-level @validate, and group constraints have all passed

For property-level @read, @write, and @validate, the first argument is the pipeline value, not the owning instance. For default, schema-level @validate, and @computed, this is the instance — so these must use a function form to read this (an arrow function in a strict-mode ES module does not bind its own this). Method bodies also bind this to the owning instance (the Class constructor for static methods) — see Method bodies below.

Computed properties (@computed)

An @computed slot makes a property's value always derived from a binding, with no value stored for it. The binding runs on every read; assigning to the property is rejected, since there is nothing to assign to.

<div itemprop="@computed" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default function() { return this.firstName + " " + this.lastName; }
  </script>
</div>

this is bound to the owning instance (a function form is required to read it). If a property declares both @computed and @read, @computed wins and @read never runs for it. A legacy, Sessel-only shorthand — an @read slot whose typed item is the bare https://pagelove.org/Sessel type — is also still recognized as a computed property for backward compatibility; new schemas should prefer @computed. See Property for the full behavior, including the legacy form.

Method bodies

A Method's implementation slot accepts a JavaScript module the same way a property binding does:

<div itemprop="property" itemscope itemtype="https://pagelove.org/Method">
  <meta itemprop="name" content="greet">
  <div itemprop="parameter" itemscope itemtype="https://pagelove.org/Parameter">
    <meta itemprop="name" content="greeting">
  </div>
  <div itemprop="implementation" itemscope itemtype="https://pagelove.org/JavaScript/Module">
    <script itemprop="source" type="module">
      export default function(greeting) { return greeting + ", " + this.name + "!"; }
    </script>
  </div>
</div>

this is bound to the calling object — the schema instance for an instance method, or the Class constructor for a static method. Parameters are forwarded positionally, in the method's declared parameter order (Sessel implementations instead read each parameter by name). A method body may be async; the engine drives its returned Promise to settlement the same way an async default export settles.

Method bodies also dispatch when a schema method is invoked through page composition — a namespaced method element (<ns:method>) or an ns:method="…" attribute. There, this is the host element the method was dispatched on (read-only), arguments bind by name from the dispatch element's attributes (rather than positionally), an ambient read-only document is available, and the return value is spliced into the page. See Method Elements for the composition-side contract, and Methods for the schema-level declaration.

A method body dispatches in a third context too: when the method is called from another server-side expression — a trigger's action, a processor, a mutation handler, or a nested method call made by another method (whether that caller is written in Sessel or JavaScript). Here the call behaves like a direct instance.method(...) call: arguments are forwarded positionally in declared order, this is the receiver, and the return value is the method's value. A read-only document global is available only when the receiver is an element; a typed schema instance receives no document global and operates on this.

In this third context the method also has full access to the shared Context: it can read ambient entries such as Context.request, and any Context.foo = … assignment it makes is written back to the pass's Context — the same Context a Sessel method mutates in the same place — so a processor or trigger that reads Context afterwards observes the change. (Reading per-user request identity marks the response as user-specific, just as it does in composition.)

Whichever way a method is dispatched — through page composition (<ns:method> splicing its return into the page) or from another server-side expression — when it returns a typed schema instance it builds, that instance is treated exactly as new SchemaName { … }: its schema's @default values are filled in for any properties left unset, and it is validated against the schema (missing a required property with no default, or a wrong type, raises an error). So a method can construct and return an instance and rely on the same defaults and validation Sessel construction gives — you don't have to set defaulted properties yourself.

this and context for default

this — the in-progress instance

this is a read-only plain JS object view of the element being created. It exposes the schema-declared property keys that are already set — fields supplied by the client on the write, or fields set earlier in construction. Mutations to this inside a default expression are not preserved.

A default on one property may not read the value of another property whose default is also being computed in the same creation. Reading such a field returns undefined. Cross-property default ordering is not part of the public schema contract.

context — request and host information

context is a plain JS object passed as the first positional argument. The first cut carries a minimal set of well-known keys:

Key Type Meaning
document_html String The serialised source document being written, when one is available.

Authors must read only the keys they need and not enumerate or rely on the exact set. Future revisions may add keys.

The document global

Separately from context, a default expression also has access to a document global — a live view of the in-progress element that supports the same DOM methods as the JavaScript DOM API, including mutations (document.querySelector(...), appending or removing elements, and so on). Any changes made through document are kept: they're applied to the element being created.

Other binding kinds that also receive a document global (for example @write bindings) get a read-only version — calling a mutating method throws.

Chaining order

When a property has pipeline bindings at multiple levels of a schema inheritance chain, stages are chained:

Hook Order Combination rule
@read Ancestor-first (root → leaf) The output of one stage is the input to the next.
@write Child-first (leaf → root) The output of one stage is the input to the next.
@validate Most-derived only The child's validator completely overrides the parent's; no chaining.

Pipeline chains can mix Sessel and JavaScript freely across the inheritance hierarchy. A parent's Sessel stage feeds a child's JavaScript stage, and vice versa, in the order above.

Importing schemas

A schema import uses the schema URL as the module specifier, with a fixed type import attribute of "https://pagelove.org/Schema":

import Note from "https://moodboard.pagelove.org/Note" with { type: "https://pagelove.org/Schema" };

The schema URL is an identifier, not a fetchable URL. The module loader resolves the import at evaluation time by looking up the schema in the host's schema cache. An unknown schema fails with the unknown-schema variant.

Each import yields a JavaScript class with the schema's short name (the last path segment of the itemtype URL). The class is synthesised at evaluation time and supports construction, property access, instanceof, and method dispatch.

All other import specifiers (relative paths, bare specifiers, HTTP URLs) are rejected with the import-not-allowed variant. There is no pagelove:host module.

Working with imported classes

Operation Behaviour
new Foo({...}) Constructor accepts a plain object whose keys are schema-declared property names. Undeclared properties are stored on the instance but do not trigger pipelines.
instance.prop Declared properties are readable and writable through ordinary getter/setter pairs backed by a Symbol-keyed store.
instance instanceof Bar Walks the prototype chain. If Foo extends Bar, new Foo() instanceof Bar is true.
instance.method() Schema-declared methods appear on the class prototype. Method bodies execute their declared implementation — Sessel or JavaScript — via the cross-language call path.

Schemas inheriting from https://pagelove.org/Map produce classes that extend Map, with keys, values, entries, and merge exposed. Undeclared property reads fall through to the Map backing store.

Supported language features

Supported:

Not supported:

Math.random() and Date.now() are permitted and return legitimately different values on the server and the browser. Bindings commit logic over inputs, not clock or RNG agreement; the server's value is what gets stored.

Resource limits

Every evaluation runs under a per-request budget. In production the budget is read from the host's https://pagelove.org/TransactionBudget Microdata, shared with Sessel. A request touching one Sessel binding and one JavaScript binding sees a single shared budget, not two competing ones.

Limit Source in production Default in unbudgeted contexts Exhaustion error
Memory Remaining memory budget on the request 16 MB per context out-of-memory
Stack Per-thread default 256 KB per context threw (typically InternalError: stack overflow)
Time Remaining time budget on the request Per-thread default timeout
Ops Charged in batches against the request budget on every periodic interrupt Not charged for short, straight-line code Surfaces via the request budget

Errors

Every failure is rendered to the client as an HTML Microdata document of type https://pagelove.org/BindingFailure, nested inside the https://pagelove.org/SchemaViolation envelope.

Variant Trigger
parse The module source fails to parse as an ES module.
shape The module parsed but has no default export, or the default export is not a function.
threw The default function ran and threw. The message and (when available) stack are carried in the failure item.
timeout The evaluation exceeded the time budget.
out-of-memory The evaluation exceeded the memory budget.
marshal An input value (a field of this, or a key of context) cannot be converted to a JavaScript value.
return-type The return value cannot be converted back into a dombase value. Functions, symbols, cyclic objects, and objects nested deeper than 64 levels all fall here.
import-not-allowed The module source contains an import specifier other than pagelove:schema.
unknown-schema A pagelove:schema import referenced a schema itemtype URL not found in the host's schema cache.
unknown-language The slot carried a typed item whose itemtype URL matches no registered language.

The rendered failure carries at minimum:

<div itemscope itemtype="https://pagelove.org/BindingFailure">
  <meta itemprop="language" content="https://pagelove.org/JavaScript/Module">
  <meta itemprop="variant" content="threw">
  <p itemprop="message">TypeError: Cannot read properties of undefined (reading 'foo')</p>
  <pre itemprop="stack">    at default (eval:2:17)</pre>
</div>

The stack property is present for threw when the engine provided one and absent otherwise. Sessel bindings produce structurally identical BindingFailure items with a different language value.

Tracing

Every JavaScript evaluation produces an OpenTelemetry-compatible span named dombase_js.evaluate:

Attribute Source
schema.itemtype The schema this binding belongs to, or "(none)".
binding.kind "default", "read", "write", "validate", "computed", "schema-@validate", or "method". (Other binding contexts — triggers, processors, WebDAV auth — use their own kind values; not covered here.)
binding.source_hash Short hex-encoded fingerprint of the source.
binding.source_len Length of the source string in bytes.
outcome "ok" on success, or the failure variant name.
budget.memory_delta_bytes Bytes allocated during evaluation.
budget.time_nanos Wall-clock nanoseconds for the evaluation.

A child span dombase_js.compile wraps the compile step on the first use of a given source on a thread. Cross-language Sessel calls from within JavaScript nest as children of the dombase_js.evaluate span.

Marshalling

Values flow between dombase and JavaScript at every binding boundary:

Direction Behaviour
dombase → JS (inputs to this, context, pipeline argument) Each value is converted to its JavaScript equivalent. Values that cannot be converted fail the binding with marshal.
JS → dombase (return value) The value is converted back to a dombase value. Functions, symbols, cyclic objects, and objects nested deeper than 64 levels fail with return-type.
Date round-trips A dombase temporal value passed into this/context, or a JS Date returned from a binding, currently unmarshalls as a plain Map of the Date object's own properties rather than as a dombase temporal value. Bindings that need a temporal default should return an ISO-8601 string.
this traversal this is a placeholder object seeded only with the explicitly set schema-declared fields the marshaller currently understands. Rich traversal of the in-progress element's DOM subtree is not yet wired through.

First-cut exclusions

The following are out of scope for the current cut. Each is either a deferred feature or an interim limitation that will be lifted without breaking existing bindings:

Examples

Random coordinate default

<div itemprop="default" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default () => String(Math.floor(100 + Math.random() * 500));
  </script>
</div>

Timestamp default reading context

<div itemprop="default" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default function(context) {
      return `created at ${new Date().toISOString()}`;
    }
  </script>
</div>

Normalise on write

<div itemprop="@write" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default (val) => typeof val === 'string' ? val.trim().toLowerCase() : val;
  </script>
</div>

Format on read

<div itemprop="@read" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default (val) => typeof val === 'string' ? val.toUpperCase() : val;
  </script>
</div>

Validate at persistence

<div itemprop="@validate" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default (val) => typeof val === 'string' && val.includes('@');
  </script>
</div>

Default that constructs a schema instance

<div itemprop="default" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    import Note from "https://moodboard.pagelove.org/Note" with { type: "https://pagelove.org/Schema" };
    export default () => new Note({ title: "untitled", x: 0, y: 0 });
  </script>
</div>

Computed property combining two fields

<div itemprop="@computed" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default function() { return this.firstName + " " + this.lastName; }
  </script>
</div>

Method body using a parameter and this

<div itemprop="implementation" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default function(greeting) { return greeting + ", " + this.name + "!"; }
  </script>
</div>

See also

HTMLAnchorElement

HTMLAnchorElement

The interface for <a>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
href href string Reflects verbatim — no base-URL resolution.
target target string Reflects the content attribute verbatim.
rel rel string Reflects the content attribute verbatim.
download download string Reflects the content attribute verbatim.
hreflang hreflang string Reflects the content attribute verbatim.
type type string Reflects the content attribute verbatim.
referrerPolicy referrerpolicy enum Keywords: "" · no-referrer · no-referrer-when-downgrade · same-origin · origin · strict-origin · origin-when-cross-origin · strict-origin-when-cross-origin · unsafe-url. Missing → ""; invalid → "".

See also

JavaScript DOM API

JavaScript DOM API

JavaScript bindings — schema methods and the @read / @write / @validate / @computed resolvers declared as JavaScript modules — can traverse and build markup with a WHATWG-style DOM API. It is exposed through the ambient document global and through node/element handles.

This is a subset chosen to make isomorphic (server and browser) bindings writable; anything not listed in these pages is not available server-side. Each interface is documented on its own page:

Interfaces and instanceof

The WHATWG node interfaces exist as real classes, with working instanceof and constructor.name, in the standard hierarchy:

So p instanceof Element, p instanceof Node, and textNode instanceof CharacterData all hold — a binding can branch on node kind the same way it would in the browser. HTML elements (HTML-parsed or createElement) are HTMLElement (so htmlEl instanceof HTMLElement, and htmlEl.constructor.name is "HTMLElement"); elements in another namespace (createElementNS, e.g. SVG) are plain Element. Members are interface-scoped: reaching for a member that is not part of a node's interface yields undefined (for example textNode.tagName and element.data are both undefined) rather than throwing. Within a node's own interface, an accessor with no value returns null (for example element.parentNode on a detached element).

Per-tag element interfaces. Every non-deprecated HTML tag that has its own dedicated interface in the WHATWG spec has one here too, below HTMLElement — an <a> is an HTMLAnchorElement, an <input> an HTMLInputElement, and so on (a instanceof HTMLAnchorElement, a.constructor.name === "HTMLAnchorElement"; and the whole chain up to Node holds). Each has its own reference page listing its reflected IDL attributes (a.href, img.src, input.required, …) — see the Element interfaces index for the full list of interfaces and their pages. A handful of obsolete WHATWG §16.3 elements (<font>, <marquee>, …) also have their interface, marked deprecated on their page. An HTML tag with no dedicated interface — either because the spec never gave it one (<section>, <article>, …) or it isn't yet covered — is a plain HTMLElement with no reflected properties beyond HTMLElement's own (so section.href is undefined); use getAttribute / setAttribute there. A single flattened node still backs every node internally — the interfaces are a prototype layer over it.

Availability and the read-only boundary

The ambient document global is present whenever the binding runs against a document. Whether it is writable depends on the binding slot:

Binding slot Ambient document
A default resolver (the value materialised for a new instance) Writable
@read, @write, @validate, @computed; schema methods; trigger when/action Read-only tree, writable construction
A document you create yourself with new DOMParser().parseFromString(…) Writable

A read-only ambient document protects the existing tree: mutating a node that is already in the document — setting an attribute, changing text, inserting or removing a child — throws a NoModificationAllowedError (message: "document is read-only in this binding context"). Read-only membership is a property of the tree as it stood when the binding started, not of how you reached a node: every node that was in the document is read-only through any path (document.body, querySelector, parentNode, a NodeList, classList), so a node cannot be laundered into a writable handle by reaching it a different way.

Constructing new nodes is always allowed, even against a read-only document. createElement, createElementNS, createTextNode, createComment, createDocumentFragment, and cloneNode return fresh, writable detached nodes; building a subtree from them and returning it works with the standard DOM API:

export default (title) => {
  const li = document.createElement("li");
  li.textContent = title;
  return li;   // return an element — see "Returning DOM"
};

The one thing you cannot do is move a node out of the read-only tree into your constructed subtree — that would mutate the tree it belongs to, so card.appendChild(document.querySelector("li")) throws NoModificationAllowedError. To reuse existing content, copy it with cloneNode(true), which yields a writable copy you can attach freely:

const copy = document.querySelector("li").cloneNode(true);
card.appendChild(copy);   // fine — a clone is a fresh, writable node

Mutations to a writable ambient document (a default resolver, or a document you parsed yourself) are serialised back and persisted after the binding returns.

Returning DOM from a binding

The value a binding returns is spliced into the composed document:

Returned value Result
An element node Serialised and spliced in place.
A NodeList or array of elements Each element serialised and spliced, in order.
A non-element node (text, comment, document, fragment) An error — the message tells you the fix, e.g. return document.documentElement instead of the document, or use .textContent instead of a text node.

Errors

Thrown errors are DOMException instances with the standard name/code/message. new DOMException(message?, name?) is available, and the full legacy name → code table is supported — see the DOMException reference. The names actually raised by this API:

Name Raised when
SyntaxError Invalid CSS selector; invalid insertAdjacentHTML position.
HierarchyRequestError A tree mutation would create a cycle.
NotFoundError removeChild / insertBefore / replaceChild reference is not a child.
NamespaceError Malformed qualified name in createElementNS / setAttributeNS.
NoModificationAllowedError Mutating a node already in a read-only tree, or moving such a node into a constructed subtree (copy it with cloneNode(true) instead); outerHTML set on a parentless element.

Divergences from the browser DOM

See also

Document

Document

Members of the Document interface, reached through the ambient document global: querying the tree, creating nodes, and reaching the document's structural elements. The factories are mutation-guarded and throw NoModificationAllowedError on a read-only document.

Querying

querySelector

querySelector(selector) → the first matching element, or null. An invalid selector throws SyntaxError.

Divergence: it scans the whole document even when called on an element (not the receiver's subtree).

const title = document.querySelector("main h1");

querySelectorAll

querySelectorAll(selector) → a static NodeList of every match. Invalid selector throws SyntaxError. Also a whole-document scan.

for (const li of document.querySelectorAll("ul#todo > li")) {
  li.classList.add("seen");
}

getElementById

getElementById(id) → the element with that id, or null. The match is a literal string comparison on the id attribute — no CSS parsing, so ., :, and [ match literally. Scoped to the receiver's subtree (a divergence from the browser, where it is always document-wide).

const cart = document.getElementById("cart");

getElementsByTagNameNS

getElementsByTagNameNS(namespace, localName) → a NodeList, scoped to the receiver's descendants (excluding the receiver). "*" matches any namespace or any local name.

const cells = row.getElementsByTagNameNS("*", "td");

Creating nodes

Factory methods returning detached nodes. All are mutation-guarded.

createElement

createElement(tag) → a detached element. tagName later reports the tag uppercased (no namespace).

const li = document.createElement("li");
li.textContent = "New item";

createElementNS

createElementNS(namespace, qualifiedName) → a detached namespaced element. qualifiedName is stored verbatim (case preserved); namespace is recorded as the element's namespace URI. Throws NamespaceError for a malformed qualified name (empty, more than one :, a leading/trailing :, or a prefix with an empty namespace). No xmlns: declaration is auto-emitted.

const g = document.createElementNS("http://www.w3.org/2000/svg", "g");

createTextNode

createTextNode(data) → a detached text node.

const t = document.createTextNode("Hello");

createComment

createComment(data) → a detached comment node.

const c = document.createComment("build: 2026-07-02");

createDocumentFragment

createDocumentFragment() → a detached fragment. Appending the fragment moves its children into the target (leaving the fragment empty).

const frag = document.createDocumentFragment();
for (const name of names) {
  const li = document.createElement("li");
  li.textContent = name;
  frag.appendChild(li);
}
list.appendChild(frag);   // moves every <li> in at once

Document structure

Accessors that reach the document's structural elements — each returns the element or null.

documentElement

The root element (<html>).

const lang = document.documentElement.getAttribute("lang");

head / body

The <head> and <body> elements.

document.body.classList.add("ready");

See also

Schema definitions in HTML

Schema definitions in HTML

A schema definition is an HTML element marked up with Microdata that pagelove.mjs reads on load to learn the shape of a record type.

When to reach for it

Reach for a schema definition whenever a new kind of record needs to exist on the page — a Note, a Post, a Comment — and pagelove.mjs must know how to create, render, and bind instances of it client-side.

Anatomy of a schema definition

A schema definition is a <div> (or any element) carrying itemscope and itemtype="https://pagelove.org/Schema". #discoverSchemas() walks every such element on the page.

Child Required Purpose
<meta itemprop="type" content="…"> yes The URL that names this schema. Instances reference it via itemtype.
<meta itemprop="parent" content="…"> no URL of another schema to inherit properties from.
[itemprop="property"] children one or more Each declares a single property. See below.

A schema with no type child is skipped silently.

Property definitions

Each property is an inner itemscope of type https://pagelove.org/Property. A <li> is conventional, but any element works. Its children declare the four fields:

Field Required Accepts
<meta itemprop="name" content="…"> yes The property name. Properties without a name are dropped.
<meta itemprop="type" content="…"> optional A type URL such as https://pagelove.org/Text, Integer, DateTime, or a nested schema URL. Defaults to the empty string if absent.
<meta itemprop="cardinality" content="…"> optional 0..1, 1..1, 0..n, 1..n. Defaults to 0..1 if absent.
itemprop="default" child optional Either a <meta> with a content string, or an embedded client-side JavaScript/Module (see below).

An additional itemprop="@read" child may carry an embedded client-side JavaScript/Module that transforms the value on read.

Inheritance

A schema may declare <meta itemprop="parent" content="…"> pointing at another schema's type URL. #discoverSchemas() resolves inheritance in a second pass:

Only direct property-name collisions override; unrelated parent properties remain.

Static defaults

Place <meta itemprop="default" content="…"> directly inside a property's itemscope. The value is always a string and is used as-is when a new instance is created.

Client-side dynamic defaults

For defaults that must be computed, embed a JavaScript/Module inside the property:

<li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
  <meta itemprop="name" content="createdAt">
  <meta itemprop="type" content="https://pagelove.org/DateTime">
  <div itemprop="default" itemscope itemtype="https://pagelove.org/JavaScript/Module">
    <script itemprop="source" type="module">
      export default () => new Date().toISOString();
    </script>
  </div>
</li>

When pagelove.mjs loads the schema on a page, its loadModule helper finds the wrapper, reads the child <script itemprop="source">, wraps the script text in a Blob, creates a Blob URL with URL.createObjectURL, imports that URL as an ES module, and assigns the module's default export as the property's default. This happens in the browser, on page load, not on the server. The module is invoked whenever pagelove.mjs needs a default value client-side — typically when a new instance is about to be created before the POST.

The @read transform

Same embedding pattern, but the wrapper's itemprop is @read instead of default:

<div itemprop="@read" itemscope itemtype="https://pagelove.org/JavaScript/Module">
  <script itemprop="source" type="module">
    export default (value) => value.toUpperCase();
  </script>
</div>

pagelove.mjs loads this module the same way — Blob URL, dynamic import, default export — and calls it to transform the property value when a client-side consumer reads the property. Like dynamic defaults, @read runs in the browser.

Examples

A schema with static defaults

<div itemscope itemtype="https://pagelove.org/Schema">
  <meta itemprop="type" content="https://schema.host/Note">
  <ul>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="title">
      <meta itemprop="type" content="https://pagelove.org/Text">
      <meta itemprop="cardinality" content="1..1">
      <meta itemprop="default" content="Untitled">
    </li>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="body">
      <meta itemprop="type" content="https://pagelove.org/Text">
    </li>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="color">
      <meta itemprop="type" content="https://pagelove.org/Text">
      <meta itemprop="default" content="#ffd166">
    </li>
  </ul>
</div>

A schema that inherits from a parent

<div itemscope itemtype="https://pagelove.org/Schema">
  <meta itemprop="type" content="https://schema.host/Content">
  <ul>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="title">
      <meta itemprop="type" content="https://pagelove.org/Text">
      <meta itemprop="cardinality" content="1..1">
    </li>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="body">
      <meta itemprop="type" content="https://pagelove.org/Text">
    </li>
  </ul>
</div>

<div itemscope itemtype="https://pagelove.org/Schema">
  <meta itemprop="type" content="https://schema.host/Post">
  <meta itemprop="parent" content="https://schema.host/Content">
  <ul>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="publishedAt">
      <meta itemprop="type" content="https://pagelove.org/DateTime">
    </li>
  </ul>
</div>

Post inherits title and body from Content and adds publishedAt. A title property declared on Post would override the parent's.

A schema with a client-side dynamic default

<div itemscope itemtype="https://pagelove.org/Schema">
  <meta itemprop="type" content="https://schema.host/Event">
  <ul>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="label">
      <meta itemprop="type" content="https://pagelove.org/Text">
    </li>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="createdAt">
      <meta itemprop="type" content="https://pagelove.org/DateTime">
      <div itemprop="default" itemscope itemtype="https://pagelove.org/JavaScript/Module">
        <script itemprop="source" type="module">
          export default () => new Date().toISOString();
        </script>
      </div>
    </li>
  </ul>
</div>

When pagelove.mjs builds a new Event in the browser, it calls the module's default export and stamps createdAt with the current time in the user's browser before the instance is posted.

Not supported client-side

pagelove.mjs's schema discovery only reads name, type, cardinality, a static or dynamic default, and a @read transform from each property — it does not implement computed properties (@computed), methods (itemtype="https://pagelove.org/Method"), or schema-level @validate. Declaring any of these in a schema the client library discovers is inert: the extra markup is silently ignored.

All three are real, server-side features — see JavaScript in schemas for computed properties, methods, and schema-level @validate as core evaluates them.

See also

HTMLAreaElement

HTMLAreaElement

The interface for <area>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
alt alt string Reflects the content attribute verbatim.
href href string Reflects verbatim — no base-URL resolution.
target target string Reflects the content attribute verbatim.
download download string Reflects the content attribute verbatim.
rel rel string Reflects the content attribute verbatim.
hreflang hreflang string Reflects the content attribute verbatim.
type type string Reflects the content attribute verbatim.
shape shape string Reflects the content attribute verbatim.
coords coords string Reflects the content attribute verbatim.
referrerPolicy referrerpolicy enum Keywords: "" · no-referrer · no-referrer-when-downgrade · same-origin · origin · strict-origin · origin-when-cross-origin · strict-origin-when-cross-origin · unsafe-url. Missing → ""; invalid → "".

See also

HTML bindings

HTML bindings

An HTML binding is a data-bind* attribute on a view element that pagelove.mjs uses to populate that element from a schema instance — and, when the element is editable, to write user edits back into the schema.

When to reach for it

Reach for a binding whenever a view element needs to show a value from a schema article, or whenever a user edit on the view needs to flow back into the record. Bindings are how the rendered light-DOM view of an instance stays in sync with the underlying <article> without any imperative wiring.

The three binding attributes

Attribute Direction What it does
data-bind="prop" two-way (when the element is editable) The element's text content (or value, on form controls) reflects the named property. User edits are written back to the schema article.
data-bind-attr="prop1 prop2" read-only Forwards each named property to a data-* attribute on the view root itself. color becomes data-color, x becomes data-x. Useful for CSS hooks.
data-bind-<htmlattr>="prop" read-only Binds one specific HTML attribute to a property value. data-bind-href="url" sets href, data-bind-src="photo" sets src, data-bind-datetime="publishedAt" sets datetime.

Property lookup is always scoped: pagelove.mjs resolves each prop against the direct [itemprop="<prop>"] children of the current schema scope, not against descendants.

Two-way updates

A data-bind element participates in writeback when user input reaches it through one of the delegated DOM events handled by pagelove.mjs:

Event Target selector Purpose
change any [data-bind] Commit on form-control change (checkbox, select, native date picker).
focusout [contenteditable][data-bind], input[data-bind], select[data-bind], textarea[data-bind] Commit when the element loses focus after editing.
input the same editable selectors Live commits, debounced so each keystroke does not hit the schema.

[contenteditable] elements participate automatically because they fire focusout and input the same way <input> and <textarea> do. No extra markup is required to make a contenteditable heading writeable — the data-bind attribute is enough.

Form controls (input, select, textarea) read and write through the element's value. Every other element reads and writes through textContent. Writes are idempotent: the binder compares before writing, so an unchanged value produces no DOM mutation.

Repetition

A single data-bind element can stamp multiple view elements when the matching schema property repeats. Two conditions trigger repetition:

#repeatElement() performs the stamp. The original element is removed from the DOM and replaced with a comment marker of the form <!--data-bind:<prop>-->. For each matching schema child, a clone of the stamp is inserted after the marker. If the schema child has no itemscope, the clone receives the scalar value written into its text content. If the schema child is itself an itemscope, the clone is linked to it via data-for="<schemaId>" and #populateBindings() recurses into the clone against the nested schema scope.

Nested scopes

A data-bind that sits inside a deeper [data-for] element is owned by that inner scope, not by the outer pass. During the outer viewRoot.querySelectorAll('[data-bind]') iteration, any element whose closest [data-for] ancestor is not the current viewRoot is skipped. The same rule applies to the data-bind-<htmlattr> sweep. This is what allows nested components to manage their own bindings without the parent rewriting them on every pass.

Examples

Two-way text binding on a heading

<template itemtype="https://schema.host/Note">
  <article class="note">
    <h1 data-bind="title" contenteditable></h1>
    <p data-bind="body" contenteditable></p>
  </article>
</template>

The heading and paragraph reflect the instance's title and body. Editing either in place commits back to the schema article on focusout and during input (debounced).

Forwarding properties as data-* attributes

<template itemtype="https://schema.host/StickyNote">
  <article class="sticky" data-bind-attr="color x y">
    <h1 data-bind="title" contenteditable></h1>
  </article>
</template>

The root <article> receives data-color, data-x, and data-y reflecting the matching properties on the instance. CSS can then read them:

.sticky { background: attr(data-color); transform: translate(attr(data-x px), attr(data-y px)); }

Binding an HTML attribute

<template itemtype="https://schema.host/Link">
  <article>
    <a data-bind-href="url" data-bind="label"></a>
    <time data-bind-datetime="publishedAt" data-bind="publishedAt"></time>
  </article>
</template>

The <a> gets its href from url and its visible text from label. The <time> gets its datetime attribute from publishedAt and its visible text from the same property.

See also

HTMLAudioElement

HTMLAudioElement

The interface for <audio>. Extends HTMLMediaElementHTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLMediaElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

Element

Element

The element surface: identity, attributes, content, classList, element-only traversal, and insertion. All setters and mutators are guarded and throw NoModificationAllowedError on a read-only document. Tree mutation shared with every node (appendChild, remove, …) lives on the Node page.

Identity

Read-only accessors describing the element:

Accessor Value
tagName Tag name — uppercased for no-namespace elements (HTML-parsed and createElement), verbatim for createElementNS.
localName The part after the first :.
prefix The namespace prefix, or null.
namespaceURI The resolved namespace URI (stored, or walked from an ancestor xmlns:*), or null.
id The id attribute, or "".
className The whole class attribute, or "".
const el = document.querySelector("svg > g");
el.tagName;        // "G"  (or verbatim if created with createElementNS)
el.id;             // "" when absent

Attributes

A set of high-frequency elements expose reflected IDL properties that read and write the matching content attribute — a.href, img.src/img.alt, input.type/input.value/input.required, and other form-control properties (see Reflected IDL attributes below and per-tag interfaces). Elements outside that set are a plain HTMLElement with no reflected properties. Either way, the getAttribute / setAttribute methods below work on every element and are the general mechanism.

getAttribute

getAttribute(name) → the value, or null when absent.

const href = link.getAttribute("href");

hasAttribute

hasAttribute(name) → boolean.

if (input.hasAttribute("required")) { /* … */ }

setAttribute

setAttribute(name, value) — sets or replaces the attribute. Guarded.

link.setAttribute("rel", "noopener");

removeAttribute

removeAttribute(name) — removes it; a no-op when absent. Guarded.

input.removeAttribute("disabled");

getAttributeNS / setAttributeNS / removeAttributeNS

The namespaced variants. getAttributeNS(ns, localName) resolves the URI to an in-scope xmlns: prefix, then reads prefix:localName (null if no in-scope prefix maps the URI). setAttributeNS(ns, qualifiedName, value) stores the attribute under qualifiedName verbatim — the ns argument is used only to validate the qualified name (throws NamespaceError if malformed). removeAttributeNS(ns, localName) resolves URI → prefix and removes prefix:localName.

el.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#icon");
el.getAttributeNS("http://www.w3.org/1999/xlink", "href");   // "#icon"

Reflected IDL attributes

For a set of high-frequency element interfaces, common IDL properties are reflected: reading the property returns the content attribute (or "" when absent, false for boolean properties), and writing it sets — or, for a falsy boolean, removes — the attribute. They are exactly equivalent to getAttribute/setAttribute on the underlying attribute; use whichever reads better.

const a = document.querySelector("a");
a.href;                       // reads the href attribute ("" if absent)
a.href = "/next";             // sets it — a.getAttribute("href") === "/next"
const input = document.querySelector("input");
input.required = true;        // adds the boolean attribute
input.required;               // → true   (input.hasAttribute("required"))

Every interface has its own reference page, listing its reflected properties (see Reflected properties: shared semantics below for how numeric/enum/boolean reflection works in general):

Interface Tag(s)
HTMLElement (any tag with no more specific interface below)
HTMLAnchorElement <a>
HTMLAreaElement <area>
HTMLAudioElement <audio>
HTMLBRElement <br>
HTMLBaseElement <base>
HTMLBodyElement <body>
HTMLButtonElement <button>
HTMLCanvasElement <canvas>
HTMLDListElement <dl>
HTMLDataElement <data>
HTMLDataListElement <datalist>
HTMLDetailsElement <details>
HTMLDialogElement <dialog>
HTMLDirectoryElement <dir>
HTMLDivElement <div>
HTMLEmbedElement <embed>
HTMLFieldSetElement <fieldset>
HTMLFontElement <font>
HTMLFormElement <form>
HTMLFrameElement <frame>
HTMLFrameSetElement <frameset>
HTMLHRElement <hr>
HTMLHeadElement <head>
HTMLHeadingElement <h1>, <h2>, <h3>, <h4>, <h5>, <h6>
HTMLHtmlElement <html>
HTMLIFrameElement <iframe>
HTMLImageElement <img>
HTMLInputElement <input>
HTMLLIElement <li>
HTMLLabelElement <label>
HTMLLegendElement <legend>
HTMLLinkElement <link>
HTMLMapElement <map>
HTMLMarqueeElement <marquee>
HTMLMediaElement (abstract — no tag)
HTMLMenuElement <menu>
HTMLMetaElement <meta>
HTMLMeterElement <meter>
HTMLModElement <ins>, <del>
HTMLOListElement <ol>
HTMLObjectElement <object>
HTMLOptGroupElement <optgroup>
HTMLOptionElement <option>
HTMLOutputElement <output>
HTMLParagraphElement <p>
HTMLParamElement <param>
HTMLPictureElement <picture>
HTMLPreElement <pre>
HTMLProgressElement <progress>
HTMLQuoteElement <blockquote>, <q>
HTMLScriptElement <script>
HTMLSelectElement <select>
HTMLSlotElement <slot>
HTMLSourceElement <source>
HTMLSpanElement <span>
HTMLStyleElement <style>
HTMLTableCaptionElement <caption>
HTMLTableCellElement <td>, <th>
HTMLTableColElement <col>, <colgroup>
HTMLTableElement <table>
HTMLTableRowElement <tr>
HTMLTableSectionElement <thead>, <tbody>, <tfoot>
HTMLTemplateElement <template>
HTMLTextAreaElement <textarea>
HTMLTimeElement <time>
HTMLTitleElement <title>
HTMLTrackElement <track>
HTMLUListElement <ul>
HTMLVideoElement <video>

† = a deprecated element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); its interface exists only for instanceof / constructor.name and content-attribute reflection fidelity — the tag is obsolete and should not be used in new content. Some interfaces cover more than one tag (blockquote/q, ins/del, the table sections/cells/cols, the six headings h1h6). video and audio are HTMLMediaElement subclasses: video instanceof HTMLVideoElement and video instanceof HTMLMediaElement both hold, and both inherit the shared HTMLMediaElement properties (so video.autoplay and audio.controls work), while video-only properties like poster are undefined on an audio.

Reflected properties: shared semantics

Numeric IDL attributes (e.g. td.colSpan/rowSpan, ol.start, img/canvas/video width/height, progress.value/max, meter.*) reflect as the browser's coerced number with per-attribute defaults and clamping — e.g. unset td.colSpan is 1. Enumerated IDL attributes (e.g. input.type, form.method, img/iframe loading, referrerPolicy, and the global dir/inputMode/enterKeyHint/autocapitalize on HTMLElement) canonicalize to their keyword with WHATWG missing/invalid defaults — e.g. unset input.type is "text". One enumerated attribute takes a non-standard shape: crossOrigin is a nullable enum — a missing attribute reflects as null, any present value other than "use-credentials" maps to "anonymous", and assigning null removes the attribute. A few attributes reflect as a string even though the WHATWG IDL might suggest otherwise: embed/object width/height, ol.type, area.shape/coords (verbatim, uncanonicalized, case preserved), and the deprecated §16.3 interfaces' numeric-looking attributes (marquee.*). contentEditable (on HTMLElement) is reflected through a bespoke accessor, not the enum path — see its page for the getter/setter shape.

A property is only present on its own interface — img.href is undefined, not an error (see interface scoping). Two intentional divergences: value-like properties (input.value, option.value, textarea.value) reflect the content attribute (the browser's defaultValue), not live editing state, because the server DOM is static; and URL properties (.href, .src) reflect verbatim with no base-URL resolution.

Content

textContent is documented with the Node content members. The HTML-string members below are element-only.

innerHTML

Get returns the serialised child content. Set parses only the assigned string — the document is never re-serialised and re-parsed. Guarded.

section.innerHTML = "<p>Loaded.</p>";

outerHTML

Get returns the element and its children serialised. Set replaces the element within its parent; throws NoModificationAllowedError if the element has no parent. Guarded.

placeholder.outerHTML = "<img src='/logo.svg' alt='Logo'>";

insertAdjacentHTML

insertAdjacentHTML(position, html) — parses html and inserts it at position (case-insensitive): beforebegin, afterbegin, beforeend, afterend. An invalid position throws SyntaxError; beforebegin/afterend on a parentless node are no-ops. Guarded.

list.insertAdjacentHTML("beforeend", "<li>Appended</li>");

classList

element.classList is a live DOMTokenList over the class attribute — the single source of truth (emptying the list removes the attribute). Mutators are guarded. It is iterable ([...classList], Array.from(classList)).

Member Behaviour
add(...tokens) Adds tokens (deduped, order preserved).
remove(...tokens) Removes every listed token.
toggle(token, force?) → boolean Adds/removes; force pins the outcome. Returns whether the token is now present.
replace(old, new) → boolean Replaces old with new (set semantics); returns whether a replacement happened.
contains(token) → boolean Membership test.
item(index) → string / null The token at index (negative → null).
length Token count.
value (get/set) The whole class string.
el.classList.add("active", "highlight");
el.classList.toggle("open");            // → true (now present)
el.classList.replace("active", "done"); // → true
if (el.classList.contains("done")) { /* … */ }

Element traversal

Element-only navigation (skipping text and comment nodes). Each returns an element or null except the count. See Node for the all-kinds accessors (firstChild, nextSibling, …).

Accessor Value
children A static NodeList of child elements.
firstElementChild / lastElementChild First / last child element, or null.
childElementCount Number of child elements.
nextElementSibling / previousElementSibling Adjacent sibling element, or null.
for (const row of table.children) { /* each <tr> */ }

closest

closest(selector) → the nearest inclusive ancestor matching the selector, or null. Receiver-scoped. Invalid selector throws SyntaxError.

const form = submitButton.closest("form");

matches

matches(selector) → boolean. Invalid selector throws SyntaxError.

if (el.matches("a[href^='https://']")) { /* external link */ }

Insertion convenience

The WHATWG convenience mutators. String arguments become text nodes. before/after/replaceWith are no-ops on a detached node. All guarded.

Method Behaviour
append(...nodes) Insert at the end of this element's children.
prepend(...nodes) Insert at the start.
before(...nodes) / after(...nodes) Insert as a sibling before / after this element.
replaceWith(...nodes) Replace this element (it detaches but stays live).
remove() Detach this element from its parent.
heading.after(document.createElement("hr"));
oldBanner.replaceWith("Plain text now");   // string → text node
staleNode.remove();

See also

Declarative commands

Declarative commands

A declarative command is a command="..." attribute on a <button> that pagelove.mjs recognizes and turns into a schema mutation — creating a new instance or deleting an existing one — without any application code.

When to reach for it

Reach for a declarative command whenever a button should add a new schema instance to a view or remove an existing one. The runtime handles the DOM update and the network call; the markup carries all the intent.

Supported commands

command= value What it does
--create-instance Creates a new instance of the schema named by the button's data-schema attribute and appends it to the target element.
--remove-instance Deletes the schema instance referenced by the button's nearest [data-for] ancestor.

Only these two values are acted on by the command handler. Any other command= value on a button inside the view is ignored.

Button attributes

Attribute Required for Purpose
command both Names the action. Must be --create-instance or --remove-instance.
data-schema --create-instance URL of the schema type to instantiate.
commandfor --create-instance (outside templates) ID of the target element the new instance is appended to.

--remove-instance takes no attributes of its own — it infers its target from the nearest [data-for] ancestor of the button.

How the button is wired

pagelove.mjs dispatches command buttons through two delivery paths:

Path Where it fires How the button is found
Native command event On the element named by commandfor The runtime attaches a command listener to every element referenced by a commandfor on a [command] button at startup.
Delegated click On the view root The runtime listens for clicks anywhere inside the view and routes any [command] button that has no commandfor attribute through the same handler.

The delegated path is what makes commands work inside <template> content, where commandfor cannot point at an element that does not yet exist.

Where the target comes from

For --create-instance:

Button location Target element
Inside a [data-for] view element The schema element whose ID matches [data-for].
Anywhere else The element referenced by commandfor (resolved by the native command event).

For --remove-instance, the target is always the schema element referenced by the nearest [data-for] ancestor. A button with no [data-for] ancestor does nothing.

Inferred itemprop on the new article

After creating the new <article>, pagelove.mjs inspects the target's itemtype. If the target has one, the runtime looks up that schema and searches its property list for a property whose type matches the new instance's type. If a match is found, the new article is given that itemprop. If nothing matches, no itemprop is set.

Optimistic behavior

Both commands update the DOM first and persist in the background.

Command DOM step Network step
--create-instance Pagelove.create(typeUrl) builds the article and target.appendChild(article) inserts it immediately. target.POST(article) runs in the background when the target supports POST. The promise is stashed as article._pendingPost so later writes can await it.
--remove-instance The schema element's etag is cleared and schemaEl.remove() detaches it immediately. DELETE() is called on the detached element if it exposes one.

Examples

Creating a new note

<main id="canvas" itemscope itemtype="https://schema.host/Board">
  <!-- existing notes -->
</main>

<button
  command="--create-instance"
  commandfor="canvas"
  data-schema="https://schema.host/StickyNote">
  Add note
</button>

Activating the button creates a StickyNote article and appends it to #canvas. If Board declares a property of type StickyNote, the new article is tagged with that itemprop automatically.

Deleting the current item from inside a template

<template itemtype="https://schema.host/StickyNote">
  <article class="sticky">
    <h1 data-bind="title" contenteditable></h1>
    <button command="--remove-instance">Delete</button>
  </article>
</template>

Each stamped view sits inside a [data-for] wrapper pointing at its backing article. Clicking the Delete button removes that article from the DOM and fires DELETE() against it.

See also

HTMLBRElement

HTMLBRElement

The interface for <br>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

Node

Node

Members shared by every node — the document, elements, text, comments, and fragments alike: traversal, tree mutation, character data, and metadata. Element-only navigation (children, firstElementChild, …) is on the Element page. All mutators are guarded and throw NoModificationAllowedError on a read-only document.

Traversal

All-kinds navigation (text and comment nodes are included). Each returns a handle or null.

Accessor Value
parentNode The parent, or null.
parentElement The parent only if it is an element, else null.
firstChild / lastChild First / last child of any kind, or null.
previousSibling / nextSibling Adjacent sibling of any kind, or null.
childNodes A static NodeList of all child kinds.
ownerDocument The owning document — null when called on the document itself.

hasChildNodes

hasChildNodes() → boolean.

if (node.hasChildNodes()) {
  for (const child of node.childNodes) { /* text and elements */ }
}

Metadata

Accessor Value
nodeType The numeric type code — compare against the Node constants.
nodeName Element = uppercased tag; otherwise #text, #comment, #document, #document-fragment, the doctype name, or a PI target.
if (node.nodeType === Node.ELEMENT_NODE) { /* it's an element */ }

Character data

textContent

Get concatenates all descendant text (a comment yields its own data). Set replaces every child with a single text node — an empty string leaves no children. Available on every node; guarded.

cell.textContent = "42";
const words = article.textContent.split(/\s+/).length;

data / length

data (get/set) and length (get) are CharacterData members, so they apply to text and comment nodes: data is the character payload, length its Unicode character count. On a node of any other interface they are out of scope, so element.data and element.length are undefined. Setting data is guarded.

const c = document.createComment("draft");
c.data;          // "draft"
c.length;        // 5
c.data = "final";

Tree mutation

A node from another document is adopted (deep-copied); a DocumentFragment argument moves its children (leaving the fragment empty).

appendChild

appendChild(child) → the appended child. Appending a node to its own descendant or itself throws HierarchyRequestError.

list.appendChild(document.createElement("li"));

insertBefore

insertBefore(node, reference) → the inserted node. A null/omitted reference behaves like appendChild; otherwise reference must be a current child, else NotFoundError.

list.insertBefore(newItem, list.firstChild);   // insert at the top

removeChild

removeChild(child) → the removed child (which stays live with parentNode === null). child must be a child, else NotFoundError.

list.removeChild(list.lastChild);

replaceChild

replaceChild(newNode, oldNode)oldNode. oldNode must be a child, else NotFoundError.

list.replaceChild(document.createElement("li"), staleItem);

cloneNode

cloneNode(deep?) → a detached clone (deep defaults to false). Rejected on a read-only document — the clone would allocate into the read-only arena.

const copy = template.cloneNode(true);

contains

contains(other) → boolean; false across documents.

if (main.contains(node)) { /* node is inside <main> */ }

Node constants

The Node global exposes the standard node-type constants, for comparison against nodeType:

Node.ELEMENT_NODE (1) · Node.TEXT_NODE (3) · Node.COMMENT_NODE (8) · Node.DOCUMENT_NODE (9) · Node.DOCUMENT_TYPE_NODE (10) · Node.DOCUMENT_FRAGMENT_NODE (11)

See also

NodeList

NodeList

Query results and child lists are a single static NodeList type. There is no separate HTMLCollectionchildren also returns a NodeList. It is a snapshot taken when produced: later mutations to the tree are not reflected.

A NodeList backs childNodes, children, querySelectorAll, and getElementsByTagNameNS.

Members

Member Behaviour
length The number of nodes.
item(index) The node at index, or null (negative or out-of-range → null).

It is iterablefor…of, spread, and Array.from all work.

const items = document.querySelectorAll("li");

items.length;        // e.g. 3
items.item(0);       // first <li>, or null
items.item(-1);      // null (no negative indexing)

for (const li of items) {
  li.classList.add("counted");
}

const titles = Array.from(items, li => li.textContent);

Because a NodeList is a snapshot, removing a node during iteration does not shorten the list — the snapshot still holds every node that matched when it was produced.

See also

Web Components

Web Components

A Pagelove Web Component is a real custom element, auto-defined by pagelove.mjs from a <template itemtype> whose root tag is hyphenated, extending the PageloveComponent base class so its light-DOM view stays in sync with its backing schema article.

When to reach for it

Reach for a Web Component when a template is a live, interactive element with its own lifecycle — drag, resize, mixin behavior, or any API the rest of the page will call. Give the template root a hyphenated tag (<sticky-note>, <kanban-card>) and the runtime takes care of the rest.

Auto-defined custom elements

On boot, pagelove.mjs walks every <template itemtype> it has discovered and inspects template.content.firstElementChild. The auto-definition rule is:

Condition Result
Root tag contains a - and is not already registered A class extending PageloveComponent is defined via customElements.define, with static itemtype set to the template's itemtype.
Root tag contains no - Skipped — renders as a plain DOM fragment.
Root tag already registered Skipped — the existing registration wins, so apps can pre-register subclasses before pagelove.mjs runs.
Same tag is the root of two templates with different itemtypes The runtime throws — a custom element can only represent one schema type.

Any mixins whose selectors match the template root are stacked onto the base class before customElements.define is called.

The PageloveComponent base class

PageloveComponent extends HTMLElement. It is an autonomous custom element — not a built-in extension — so the root tag itself is what the browser upgrades.

Member Purpose
static itemtype Set by the auto-definer to the schema itemtype the class represents. null on the unsubclassed base.
static binders Array of binder definitions. Ships with dataBindBinder and dataBindAttrBinder.
static create(values) Factory that calls window.pagelove.create(this.itemtype, values) to build a new schema article.
connectedCallback() Resolves the schema article from data-for, builds a propName → [{element, binder}] index from every binder's collect(), runs an initial bind, then starts a MutationObserver on the schema article.
disconnectedCallback() Disconnects the observer, clears the index, drops the schema article reference.
_get(propName) / _set(propName, value) Read and write schema properties. Used by mixins and subclasses.

The observer watches childList, subtree, characterData, and attributes (filtered to content and datetime). When a schema property becomes dirty, every indexed entry is re-applied through its binder, so schema writes flow one-way into the view.

The default binders

dataBindBinder collects every [data-bind] element under the component root and writes the named schema property to either element.value (for form controls) or element.textContent (for everything else).

dataBindAttrBinder reads the root's data-bind-attr attribute, splits on whitespace, and forwards each named property onto root.dataset.<propName> so CSS and selectors can react to schema values.

Both binders implement the rules documented on the HTML bindings page — the base class simply runs them inside its own lifecycle.

Mixins

Mixins add behavior to auto-defined components by wrapping the PageloveComponent base class before it is registered. The registry is a module-level array of (selector, mixinFn) pairs.

Function Signature Purpose
registerComponentMixin (selector, mixinFn) Push a new entry. selector is a CSS selector tested against the template root; mixinFn is a class factory of the form (Base) => class extends Base { … }.
getMatchingMixins (rootElement) Return the mixin factories whose selector matches the given root. Rarely called directly — the auto-definer uses it during discovery.

Stacking order is governed by reduceRight: mixins are applied in reverse registration order, so the earliest-registered mixin sits closest to PageloveComponent and later registrations wrap around it. Each mixin should call super.connectedCallback?.() and super.disconnectedCallback?.().

Built-in mixins

Three mixins ship with the component module and auto-register themselves on import.

Mixin Auto-registered selector Reads / writes What it does
Draggable [data-draggable] writes data-x, data-y Pointer-driven positioning. On pointerdown (or inside a [data-drag-handle] descendant if one exists), it tracks the pointer and updates inline left / top for live feedback. On release it writes dataset.x / dataset.y, which the runtime commits to the schema as x / y.
Resizable [data-resizable] writes data-width, data-height Injects a .pl-resize-handle corner child and drives resize via pointer events. On release it writes dataset.width / dataset.height, which the runtime commits to the schema as width / height.
Stackable [data-stackable] writes data-z Click-to-front z-ordering. On pointerdown (capture phase, non-intrusive), it sets data-z to one more than the maximum data-z of its siblings, which the runtime commits to the schema as z.

Stackable also mirrors its data-z attribute to inline style.zIndex on connection and whenever the attribute changes. This keeps the stacking applied without depending on CSS attr(data-z integer), which Safari does not yet support.

Examples

Minimal custom element from a template

<template itemtype="https://schema.host/StickyNote">
  <sticky-note>
    <h1 data-bind="title" contenteditable></h1>
    <p  data-bind="body"  contenteditable></p>
  </sticky-note>
</template>

The root is hyphenated, so pagelove.mjs defines <sticky-note> as a PageloveComponent subclass. Each stamped instance binds title and body through dataBindBinder.

Draggable, resizable, and stackable without writing any JavaScript

<template itemtype="https://schema.host/StickyNote">
  <sticky-note data-draggable data-resizable data-stackable>
    <h1 data-bind="title" contenteditable></h1>
    <p  data-bind="body"  contenteditable></p>
  </sticky-note>
</template>

All three built-in selectors match the template root, so the auto-definer stacks Draggable, Resizable, and Stackable onto PageloveComponent. Dragging the note commits x and y to the schema; dragging the corner handle commits width and height; clicking the note raises z so it sits above its siblings.

A custom mixin

import { registerComponentMixin } from 'https://pagelove.github.io/beta-js/pagelove/component.mjs';

registerComponentMixin('[data-glow]', (Base) => class extends Base {
  connectedCallback() {
    super.connectedCallback?.();
    this.addEventListener('pointerenter', () => this.classList.add('glowing'));
    this.addEventListener('pointerleave', () => this.classList.remove('glowing'));
  }
  disconnectedCallback() {
    super.disconnectedCallback?.();
    this.classList.remove('glowing');
  }
});

Any template root that matches [data-glow] now gets hover-glow behavior as part of its class chain, provided registration happens before pagelove.mjs discovers templates.

See also

HTMLBaseElement

HTMLBaseElement

The interface for <base>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
href href string Reflects verbatim — no base-URL resolution.
target target string Reflects the content attribute verbatim.

See also

DOMParser and XMLSerializer

DOMParser and XMLSerializer

Two globals for moving between HTML strings and DOM: parse a fresh writable document, and serialise any node back to a string.

DOMParser

parseFromString

new DOMParser().parseFromString(html, type) → a writable document. This is the way to build markup to return from a read-only binding context: the parsed document (and everything reached from it) is writable even when the ambient document is not.

Divergence: the type argument is accepted but ignored — input is always parsed as text/html.

export default () => {
  const d = new DOMParser().parseFromString("<ul></ul>", "text/html");
  const li = d.createElement("li");
  li.textContent = "Item";
  d.querySelector("ul").appendChild(li);
  return d.querySelector("ul");   // return an element to splice in
};

XMLSerializer

serializeToString

new XMLSerializer().serializeToString(node) → a string. A document serialises whole; any other node serialises as its outer HTML (a fragment emits just its children).

const html = new XMLSerializer().serializeToString(element);

Serialising is rarely needed inside a binding — returning an element splices it into the page directly (see Returning DOM from a binding). Reach for serializeToString when you need the markup as a string — for example to hash it, store it in an attribute, or compare two subtrees.

See also

The Pagelove class

The Pagelove class

Pagelove is the class that drives declarative HTML apps. Most pages don't construct it explicitly — the library auto-instantiates one on <main> at load time.

When to reach for it

Reach for the constructor directly when an app needs explicit lifecycle control, multiple view roots, commit hooks, a filtered subset of schema instances, or when Pagelove must be driven from application code instead of from the auto-start.

Loading the library

Import the module from wherever it is served:

<script type="module">
  import { Pagelove } from 'https://pagelove.github.io/beta-js/pagelove.mjs';
</script>

Merely loading pagelove.mjs is usually enough — the auto-start handles construction. See the JavaScript overview for the full loading story.

Auto-start

When the module finishes loading, it awaits ready and then checks the document. If the page has a <main> element and no Pagelove instance has been constructed by application code (_instanceCount === 0), the library runs:

document.pagelove = new Pagelove({ view: main });
await document.pagelove.start();

The instance is then reachable as document.pagelove. Auto-start is skipped if there is no <main>, or if any application code has already called new Pagelove(...) before the ready promise resolves.

Constructor

new Pagelove(config)

The single argument is a config object. Every option is read once at construction time.

Option Type Required Description
view Element required The visible view root. Typically <main>. All rendered instances are appended here.
filter string optional CSS selector that limits which discovered schema instances this Pagelove manages.
schema Element optional (legacy) Explicit schema root element. Direct [itemscope][itemtype][id] children are scanned. Prefer filter in new code.
beforeCommit (schemaEl, prop, value) => boolean optional Called before every write. Return false to reject the write.
afterCommit (schemaEl, prop, value) => void optional Called after every successful write.
onRender (viewEl, schemaEl) => void optional Called after a template stamp has been populated from a schema article.
onPatch ({ articleId, prop }) => void optional Called when a remote patch is applied to a schema article.
ensureSchemaEl (article, prop, value) => Element optional Overrides the default routine that locates or creates the [itemprop] element a write should target.

The most-recently-constructed instance is also assigned to window.pagelove so that PageloveComponent.create can delegate into it.

Methods

start()

await pagelove.start();

Discovers <template itemtype> definitions, awaits the ready promise, performs the first full render, and begins observing the document for changes. Idempotent — calling it on an already-started instance is a no-op. Returns a promise that resolves once observation is in place.

stop()

pagelove.stop();

Disconnects every observer and removes the change, focusout, and input listeners. Use it when tearing down a Pagelove-driven region without unloading the page.

populate(viewEl, schemaId)

pagelove.populate(dialog, 'item-abc123');

Populates the [data-bind] children of viewEl from the schema article whose id is schemaId, and sets viewEl.dataset.for so subsequent commits route back to that article. Use it for dialogs, side panels, or any element outside the main view. The original innerHTML is captured on first call and restored on every subsequent call, so the same element can host different schema articles in turn.

renderAll()

pagelove.renderAll();

Forces a full re-render of the view from the current schema. Existing rendered children of the view (those carrying [data-for]) are removed, and every discovered schema instance is re-stamped through its template. Schema articles that coexist inside the view are preserved.

create(typeUrl, values = {})

const article = pagelove.create('https://schema.host/MoodNote', { mood: 'curious' });

Builds a new <article> element for the named schema type, populated from values and from any defaults declared in the schema definition. The returned article carries itemscope, itemtype, a generated id, and an [itemprop] child for every defined property. Throws if no schema definition has been discovered for typeUrl.

flushPendingPatches()

pagelove.flushPendingPatches();

Applies every patch that was deferred because its target element was focused at the time. Pagelove defers remote patches to focused inputs to avoid clobbering in-flight edits; this method drains the queue on demand.

Properties

hasPendingPatches

Read-only boolean getter. Returns true when at least one remote patch has been deferred and is waiting to be applied. Pair with flushPendingPatches() for explicit drain control.

Module exports

Export What it is
Pagelove The class documented on this page.
ReactiveTemplate Backward-compat alias for Pagelove. New code should import Pagelove.
PageloveComponent Base class for Web Components, re-exported from pagelove/component.mjs.
Draggable Drag-and-drop mixin, re-exported from pagelove/component.mjs.
registerComponentMixin Mixin registration helper, re-exported from pagelove/component.mjs.
ready Promise that resolves when the initial OPTIONS discovery completes. Awaited by start() and by the auto-start.

Examples

Explicit instantiation

<main></main>
<aside id="inbox"></aside>

<script type="module">
  import { Pagelove } from 'https://pagelove.github.io/beta-js/pagelove.mjs';

  const pagelove = new Pagelove({
    view: document.querySelector('#inbox'),
    filter: '[data-folder="inbox"]',
  });

  await pagelove.start();
</script>

A second view root is mounted on #inbox, restricted to schema instances tagged with data-folder="inbox". The default auto-start is suppressed because the application constructed an instance before ready resolved.

Intercepting writes with beforeCommit

const pagelove = new Pagelove({
  view: document.querySelector('main'),
  beforeCommit(schemaEl, prop, value) {
    if (prop === 'title' && value.trim() === '') {
      return false; // reject empty titles
    }
    return true;
  },
  afterCommit(schemaEl, prop, value) {
    console.log('committed', schemaEl.id, prop, value);
  },
});

await pagelove.start();

beforeCommit runs against every prospective write. Returning false cancels the commit; returning anything truthy lets it proceed and triggers afterCommit once the write succeeds.

See also

HTMLBodyElement

HTMLBodyElement

The interface for <body>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

Server-Sent Events

Server-Sent Events

PageloveSSE is the live mutation streaming client: it opens a Server-Sent Events connection to a document, parses incoming HTML Microdata mutation events, applies them to the live DOM, and re-dispatches them as cancelable custom events on document.

When to reach for it

Reach for it when a view should update in real time as the underlying document changes — collaborative editing, live dashboards, multi-tab synchronization — without polling. For the default case, no application code is required at all: importing the module is enough.

Loading the library

Add the module to the page:

<script type="module" src="https://pagelove.github.io/beta-js/pagelove/sse.mjs"></script>

Importing pagelove/sse.mjs auto-instantiates one PageloveSSE subscribed to the current page URL. The default instance is held internally and begins streaming as soon as the module evaluates. Application code is only needed when subscribing to a different URL or when intercepting events.

The PageloveSSE class

import { PageloveSSE } from 'https://pagelove.github.io/beta-js/pagelove/sse.mjs';

Constructors

Form Subscription target
new PageloveSSE() window.location.href — the current page
new PageloveSSE(url) The given document URL

The constructor opens the underlying EventSource immediately, with withCredentials: true so cookies and authorization travel with the request.

Methods

Method Description
close() Close the underlying EventSource and drop the reference. The instance cannot be reopened — construct a new one to resubscribe.

Properties

Property Type Description
url string The URL this client is subscribed to. Read-only.
source EventSource | null The underlying EventSource, or null after close(). Read-only.

Static methods

Method Description
PageloveSSE.parse(data) Parse an HTML Microdata mutation payload. Returns { method, selector, path, host, body, etag } or null.
PageloveSSE.parseReset(data) Parse a reset payload. Returns the reason string, or "unknown" if no reason is present.

DOM mutations

When a mutation event arrives, PageloveSSE locates the target with the carried CSS selector and applies the change:

Method Action
POST Appends the new content as a child of the matched element.
PUT Replaces the matched element with the new content.
DELETE Removes the matched element.

If no element matches the selector, the event is silently dropped. Mutations that echo a local write (matched against the pending PLMethodStarted queue) are recognized as echoes and the DOM step is skipped — the local change already produced the result.

This local echo check only reconciles the same tab's own optimistic write against the mutation event that write eventually produces — it does not affect which events the server delivers. PageloveSSE connects with a plain EventSource and does not currently read the server-assigned connection token or send it back on writes (see Echo suppression), so the server falls back to its session-based suppression: a write from one browser tab is not delivered live to another tab of the same session, since same-origin tabs share the session cookie. Each tab only ever sees its own writes reflected through this local echo-matching step, not through the SSE stream. If your application needs one tab to see another same-session tab's live writes, subscribe with your own EventSource, listen for the pagelove-connection event to capture the server-assigned token, and send it back as a Pagelove-Connection header on every mutating request from that tab, as described in that section, rather than relying on the default PageloveSSE connection.

Events on document

Three custom events are dispatched on document. All three bubble and are composed.

Event When it fires Cancelable event.detail contains
PLMutation Before a parsed mutation is applied to the DOM yes — preventDefault() skips the DOM change method, selector, path, host, body, etag, element
PLMutationApplied After the mutation has been applied no Same shape as PLMutation. element is the new or modified node, or null for DELETE.
PLStreamReset When the server sends a reset event yes — preventDefault() suppresses the default location.reload() reason

PLMutation detail fields:

Field Type Description
method string HTTP method — POST, PUT, or DELETE.
selector string CSS selector of the target element.
body string HTML fragment to apply. Empty for DELETE.
path string Document path the mutation belongs to.
host string Virtual host the mutation belongs to.
etag string ETag of the resulting element, when supplied.
element Element The DOM element matched by the selector.

Listening for events

document.addEventListener('PLMutation', (event) => {
  const { method, selector, element } = event.detail;
  console.log(`incoming ${method} ${selector}`);
  // event.preventDefault(); // would skip the DOM change
});

PLMutationApplied follows the same shape and fires after the change has landed. PLStreamReset carries event.detail.reason; calling preventDefault() cancels the automatic reload.

Focus protection

Focus protection — deferring incoming changes that target the currently focused element until focus leaves — is not implemented in pagelove/sse.mjs. It lives in the Pagelove class, which observes the schema, queues patches against focused inputs, and exposes flushPendingPatches() and hasPendingPatches for explicit control.

Examples

Default — include the script

<script type="module" src="https://pagelove.github.io/beta-js/pagelove/sse.mjs"></script>

The page is now live. Any mutation the server streams for this URL is applied to the DOM as it arrives.

Manual subscription to a different URL

<script type="module">
  import { PageloveSSE } from 'https://pagelove.github.io/beta-js/pagelove/sse.mjs';

  const sidebar = new PageloveSSE('/sidebar.html');

  document.addEventListener('PLMutationApplied', (event) => {
    if (event.detail.path === '/sidebar.html') {
      console.log('sidebar updated', event.detail.selector);
    }
  });

  // Later, when the sidebar is dismissed:
  // sidebar.close();
</script>

A second subscription is opened against /sidebar.html alongside the auto-instantiated default. Both feed events to the same document listeners; consumers distinguish them by event.detail.path.

See also

DOMException

DOMException

Every error thrown by the DOM API — a guarded mutation on a read-only document, an invalid selector, a hierarchy violation — is a DOMException instance. The constructor is also available directly, for a binding that wants to raise its own DOM-shaped error.

Constructor

new DOMException(message?, name?)

Parameter Default Description
message "" Human-readable description.
name "Error" The error name — one of the standard names below, or any custom string.
throw new DOMException("no matching element", "NotFoundError");

Members

Member Value
name The name passed to the constructor ("Error" if omitted).
message The message passed to the constructor ("" if omitted).
code The legacy numeric code for name, or 0 if name is not one of the recognised legacy names.

toString

toString()"DOMException: <name>", or "DOMException: <name>: <message>" when message is non-empty.

try {
  card.setAttribute("id", "x");   // card is read-only
} catch (e) {
  e instanceof DOMException;   // true
  e.name;                      // "NoModificationAllowedError"
  e.code;                      // 7
  e.toString();                // "DOMException: NoModificationAllowedError: document is read-only in this binding context"
}

Name and legacy code

code reflects the Web IDL legacy error code for the recognised name values:

name code
IndexSizeError 1
DOMStringSizeError 2
HierarchyRequestError 3
WrongDocumentError 4
InvalidCharacterError 5
NoDataAllowedError 6
NoModificationAllowedError 7
NotFoundError 8
NotSupportedError 9
InUseAttributeError 10
InvalidStateError 11
SyntaxError 12
InvalidModificationError 13
NamespaceError 14
InvalidAccessError 15
ValidationError 16
TypeMismatchError 17
SecurityError 18
NetworkError 19
AbortError 20
URLMismatchError 21
QuotaExceededError 22
TimeoutError 23
InvalidNodeTypeError 24
DataCloneError 25

Any other name (including the default "Error") yields code === 0.

Names raised by this API

The DOM API overview lists the specific name values this implementation actually throws — SyntaxError, HierarchyRequestError, NotFoundError, NamespaceError, and NoModificationAllowedError — and the conditions that raise each one.

See also

HTMLButtonElement

HTMLButtonElement

The interface for <button>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
type type enum Keywords: submit · reset · button. Missing → "submit"; invalid → "submit".
name name string Reflects the content attribute verbatim.
value value string Reflects the content attribute verbatim.
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

Primitives

Primitives

pagelove/primitives.mjs is the low-level HTTP client that pagelove.mjs uses internally. Most apps do not touch it directly.

When to reach for it

For everything else, use the Pagelove class and the declarative flow on top.

Loading the library

<script type="module">
  import { PLDocument, PLElement } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';
</script>

The module exports two classes: PLDocument and PLElement.

The PLDocument class

A PLDocument represents a Pagelove resource URL and the live DOM associated with it.

Constructor

Form Bound document
new PLDocument() window.location.href — bound to window.document
new PLDocument(url) The given URL. If it matches window.location.href, the live document is bound; otherwise the document is fetched and parsed lazily.

Methods

Method Description
OPTIONS() Issues an OPTIONS request with Accept: multipart/mixed, parses the multipart response, and dispatches a PLCapability event on every node matching a declared selector.
createElement(element) Returns a new PLElement wrapping the given DOM node.
req(method, ...opts) Returns a bare Request targeting the document URL.

Properties

Property Type Description
url string The URL this document is bound to.
document Promise<Document> Resolves to the bound DOM document. Fetches and parses the HTML on first access if no live document is bound.

A PLDocument bound to a live Document stores a WeakRef to itself on document.pagelove and installs listeners for PLCapability and PLMethodCompleted.

The PLElement class

A PLElement wraps a single DOM node and knows how to issue HTTP requests scoped to that node.

Constructor

Form Effect
new PLElement(url) Creates an element bound to the URL with no DOM node attached yet.
new PLElement(url, element) Binds to the given DOM node. The element's ownerDocument becomes the associated document.

Methods

Method Description
GET() Fetches the element fragment, parses the response body as a single HTML node, and returns the new node.
PUT(body?) Replaces the element on the server. Body defaults to element.outerHTML; a Node body is serialized via outerHTML. Returns the raw Response.
POST(body) Posts a child fragment. The response body is parsed as a single HTML node and appended as a child of the wrapped element (unless the supplied body was already a live attached node). Throws if no body is supplied.
DELETE() Deletes the element on the server and removes it from the DOM on success.
req(method, opts) Builds the underlying Request object — sets the Range header, conditionally sets If-Match, and merges the caller's opts.

Properties

Property Type Description
url string The document URL the element is scoped against.
element Element The wrapped DOM node. Setting it also sets document from the node's ownerDocument.
document Document The DOM document the wrapped element belongs to.
selector string A stable CSS selector generated from the element. Prefers id, anchors to the nearest ancestor with an id, and falls back through itemprop, class names, role, and :nth-child(...).

OPTIONS lives on PLDocument, not PLElement — discovery is document-level.

Attached methods on DOM elements

PLDocument listens for PLCapability events on its bound document. The event payload looks like:

{
  selector: '<css selector>',
  allow: ['GET', 'PUT', 'POST', 'DELETE']
}

For each method named in allow, the document constructs a PLElement for the event target and attaches the matching method directly to the DOM node as a non-writable, configurable property:

Object.defineProperty(target, 'PUT', { value: plElement.PUT.bind(plElement), ... });

After the flow has run, element.GET(), element.PUT(body), element.POST(body), and element.DELETE() are callable on the DOM node itself with no further imports. Only methods the server has authorized appear.

ETag handling

ETags are loaded lazily, only for elements that need them.

Request format

Every request a PLElement issues is built by req(method, opts):

Header Value When
Range selector=<generated-selector> Always
If-Match <element.etag> When element.etag is a string and the method is not POST

Everything else is a standard fetch() Request. Each request also dispatches PLMethodStarted before sending and PLMethodCompleted after the response arrives. Both events bubble and carry { method, selector }; PLMethodCompleted additionally carries response.

Examples

Calling an attached method

<script type="module">
  import { PLDocument } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';

  const doc = new PLDocument();
  await doc.OPTIONS();

  document.addEventListener('click', async (event) => {
    const card = event.target.closest('article.note');
    if (card && typeof card.DELETE === 'function') {
      await card.DELETE();
    }
  });
</script>

Once OPTIONS() has run, any matching <article class="note"> exposes the methods the server allows.

Manual PLDocument and PLElement

<script type="module">
  import { PLDocument } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';

  const doc = new PLDocument('/notes.html');
  const target = document.getElementById('note-42');

  const note = await doc.createElement(target);
  await note.PUT('<article id="note-42">Edited</article>');
</script>

The wrapper is constructed by hand and no capability discovery is required. Range: selector=#note-42 is generated from the element's id; If-Match is added automatically once note.element.etag is populated.

See also

HTMLCanvasElement

HTMLCanvasElement

The interface for <canvas>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
width width number unset → 300.
height height number unset → 150.

See also

Debug channels

Debug channels

pagelove/debug.mjs provides bitwise debug channels for module-level console logging. Channels can be toggled at runtime from devtools and persist across page reloads.

When to reach for it

Reach for it to diagnose problems with SSE mutation streaming, HTTP requests and method attachment, or schema discovery and template registration. Each channel gates logs for one area of the system. Enable channels from devtools without reloading, set a breakpoint, and observe which channel is running.

Channels

The module exports four channel constants. Enable channels by bitwise OR:

Constant Bit Covers
Pagelove.SSE 1 << 0 Mutation streaming, event reception, reconnection
Pagelove.PRIMITIVES 1 << 1 HTTP requests, OPTIONS discovery, method attachment
Pagelove.SCHEMA 1 << 2 Schema discovery, template registration, component definition
Pagelove.ALL ~0 Every channel enabled

Enabling and disabling channels

Enable or disable channels with the Pagelove.debug getter/setter. To enable the SSE channel:

Pagelove.debug |= Pagelove.SSE;

Enable multiple channels at once:

Pagelove.debug = Pagelove.SSE | Pagelove.PRIMITIVES;

Enable everything:

Pagelove.debug = Pagelove.ALL;

Silence all channels:

Pagelove.debug = 0;

The mask is treated as an integer. Setting debug to a non-integer value is coerced to an int via bitwise OR with zero.

Persistence

The active channel mask is stored in localStorage.pagelove_debug when available. The mask restores automatically when the module loads, so debug settings survive page reloads and browser restarts. If localStorage is unavailable — such as in private browsing mode with storage disabled — persistence is silently skipped and the mask starts at 0.

Logging methods

Three methods gate console output against the active channel mask:

Method Behavior
Pagelove.log(channel, ...args) Calls console.log(...args) only if (Pagelove.debug & channel) !== 0
Pagelove.warn(channel, ...args) Calls console.warn(...args) under the same gating
Pagelove.error(channel, ...args) Calls console.error(...args) under the same gating

The first argument is always the channel constant; remaining arguments are passed to the console method unchanged.

Global exposure

When loaded in a browser, the module assigns itself to window.Pagelove so the debug mask can be toggled from devtools without requiring an import statement.

Examples

Turning on SSE logging from devtools

In the browser console:

Pagelove.debug |= Pagelove.SSE;

All log, warn, and error calls gated on Pagelove.SSE now appear in the console. Reload the page and the setting persists.

Logging from application code

Application modules can participate in the same gating:

import { Pagelove } from 'https://pagelove.github.io/beta-js/pagelove/debug.mjs';

function handleSSEEvent(event) {
  Pagelove.log(Pagelove.SSE, '[my-feature]', 'event received', event);
}

The log only appears when the SSE channel is enabled via Pagelove.debug |= Pagelove.SSE.

See also

HTMLDListElement

HTMLDListElement

The interface for <dl>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLDataElement

HTMLDataElement

The interface for <data>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
value value string Reflects the content attribute verbatim.

See also

HTMLDataListElement

HTMLDataListElement

The interface for <datalist>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLDetailsElement

HTMLDetailsElement

The interface for <details>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
open open boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLDialogElement

HTMLDialogElement

The interface for <dialog>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
open open boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLDirectoryElement

HTMLDirectoryElement

The interface for <dir>. Extends HTMLElementElement.

Deprecated. HTMLDirectoryElement covers an obsolete element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); it exists only for instanceof / constructor.name fidelity and content-attribute reflection, not for use in new content.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
compact compact boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLDivElement

HTMLDivElement

The interface for <div>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLElement

HTMLElement

The base interface for every HTML element. A tag with no more specific interface below is a plain HTMLElement. Extends Element.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
dir dir enum Keywords: ltr · rtl · auto. Missing or invalid → "".
inputMode inputmode enum Keywords: none · text · tel · url · email · numeric · decimal · search. Missing or invalid → "".
enterKeyHint enterkeyhint enum Keywords: enter · done · go · next · previous · search · send. Missing or invalid → "".
autocapitalize autocapitalize enum Keywords: "" · off · none · on · sentences · words · characters. offnone and onsentences are synonyms; missing or present-empty → ""; any other invalid value → "sentences" (the WHATWG Sentences default, matching Chrome).
contentEditable contenteditable string, read/write (bespoke accessor) Getter returns "true" / "false" / "plaintext-only" / "inherit" (missing or invalid → "inherit", present-empty → "true"). Setter accepts only those four keywords case-insensitively — "inherit" removes the attribute, any other value throws SyntaxError.
isContentEditable (computed) boolean, read-only Walks ancestors: the nearest ancestor (inclusive) with a defined contentEditable state of true/plaintext-only → editable; false → not editable; none found → false.

See also

HTMLEmbedElement

HTMLEmbedElement

The interface for <embed>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
type type string Reflects the content attribute verbatim.
width width string Reflects the content attribute verbatim.
height height string Reflects the content attribute verbatim.

See also

HTMLFieldSetElement

HTMLFieldSetElement

The interface for <fieldset>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
name name string Reflects the content attribute verbatim.

See also

HTMLFontElement

HTMLFontElement

The interface for <font>. Extends HTMLElementElement.

Deprecated. HTMLFontElement covers an obsolete element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); it exists only for instanceof / constructor.name fidelity and content-attribute reflection, not for use in new content.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
color color string Reflects the content attribute verbatim.
face face string Reflects the content attribute verbatim.
size size string Reflects the content attribute verbatim.

See also

HTMLFormElement

HTMLFormElement

The interface for <form>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
action action string Reflects the content attribute verbatim.
method method enum Keywords: get · post · dialog. Missing → "get"; invalid → "get".
name name string Reflects the content attribute verbatim.
target target string Reflects the content attribute verbatim.
enctype enctype enum Keywords: application/x-www-form-urlencoded · multipart/form-data · text/plain. Missing → "application/x-www-form-urlencoded"; invalid → "application/x-www-form-urlencoded".
acceptCharset accept-charset string Reflects the content attribute verbatim.

See also

HTMLFrameElement

HTMLFrameElement

The interface for <frame>. Extends HTMLElementElement.

Deprecated. HTMLFrameElement covers an obsolete element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); it exists only for instanceof / constructor.name fidelity and content-attribute reflection, not for use in new content.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.
scrolling scrolling string Reflects the content attribute verbatim.
src src string Reflects verbatim — no base-URL resolution.
frameBorder frameborder string Reflects the content attribute verbatim.
longDesc longdesc string Reflects the content attribute verbatim.
noResize noresize boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
marginHeight marginheight string Reflects the content attribute verbatim.
marginWidth marginwidth string Reflects the content attribute verbatim.

See also

HTMLFrameSetElement

HTMLFrameSetElement

The interface for <frameset>. Extends HTMLElementElement.

Deprecated. HTMLFrameSetElement covers an obsolete element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); it exists only for instanceof / constructor.name fidelity and content-attribute reflection, not for use in new content.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
cols cols string Reflects the content attribute verbatim.
rows rows string Reflects the content attribute verbatim.

See also

HTMLHRElement

HTMLHRElement

The interface for <hr>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLHeadElement

HTMLHeadElement

The interface for <head>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLHeadingElement

HTMLHeadingElement

The interface shared by <h1>, <h2>, <h3>, <h4>, <h5>, <h6>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLHtmlElement

HTMLHtmlElement

The interface for <html>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLIFrameElement

HTMLIFrameElement

The interface for <iframe>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
srcdoc srcdoc string Reflects the content attribute verbatim.
name name string Reflects the content attribute verbatim.
width width string Reflects the content attribute verbatim.
height height string Reflects the content attribute verbatim.
allow allow string Reflects the content attribute verbatim.
loading loading enum Keywords: lazy · eager. Missing → "eager"; invalid → "eager".
referrerPolicy referrerpolicy enum Keywords: "" · no-referrer · no-referrer-when-downgrade · same-origin · origin · strict-origin · origin-when-cross-origin · strict-origin-when-cross-origin · unsafe-url. Missing → ""; invalid → "".

See also

HTMLImageElement

HTMLImageElement

The interface for <img>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
alt alt string Reflects the content attribute verbatim.
width width number unset → 0.
height height number unset → 0.
srcset srcset string Reflects the content attribute verbatim.
sizes sizes string Reflects the content attribute verbatim.
loading loading enum Keywords: lazy · eager. Missing → "eager"; invalid → "eager".
decoding decoding enum Keywords: sync · async · auto. Missing → "auto"; invalid → "auto".
crossOrigin crossorigin nullable enum Keywords: anonymous · use-credentials. Missing attribute → null; any other present value → "anonymous"; assigning null removes the attribute.
referrerPolicy referrerpolicy enum Keywords: "" · no-referrer · no-referrer-when-downgrade · same-origin · origin · strict-origin · origin-when-cross-origin · strict-origin-when-cross-origin · unsafe-url. Missing → ""; invalid → "".

See also

HTMLInputElement

HTMLInputElement

The interface for <input>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
type type enum Keywords: text · search · tel · url · email · password · date · month · week · time · datetime-local · number · range · color · checkbox · radio · file · submit · image · reset · button · hidden. Missing → "text"; invalid → "text".
name name string Reflects the content attribute verbatim.
value value string Reflects the content attribute (the browser's defaultValue) — not live editing state, since the server DOM is static.
placeholder placeholder string Reflects the content attribute verbatim.
required required boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
readOnly readonly boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
checked checked boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
min min string Reflects the content attribute verbatim.
max max string Reflects the content attribute verbatim.
step step string Reflects the content attribute verbatim.
pattern pattern string Reflects the content attribute verbatim.
autocomplete autocomplete string Reflects the content attribute verbatim.

See also

HTMLLIElement

HTMLLIElement

The interface for <li>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
value value number unset → 0; negative values allowed.

See also

HTMLLabelElement

HTMLLabelElement

The interface for <label>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
htmlFor for string Reflects the content attribute verbatim.

See also

HTMLLegendElement

HTMLLegendElement

The interface for <legend>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLLinkElement

HTMLLinkElement

The interface for <link>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
href href string Reflects verbatim — no base-URL resolution.
rel rel string Reflects the content attribute verbatim.
type type string Reflects the content attribute verbatim.
media media string Reflects the content attribute verbatim.
as as string Reflects the content attribute verbatim.
crossOrigin crossorigin nullable enum Keywords: anonymous · use-credentials. Missing attribute → null; any other present value → "anonymous"; assigning null removes the attribute.
referrerPolicy referrerpolicy enum Keywords: "" · no-referrer · no-referrer-when-downgrade · same-origin · origin · strict-origin · origin-when-cross-origin · strict-origin-when-cross-origin · unsafe-url. Missing → ""; invalid → "".

See also

HTMLMapElement

HTMLMapElement

The interface for <map>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.

See also

HTMLMarqueeElement

HTMLMarqueeElement

The interface for <marquee>. Extends HTMLElementElement.

Deprecated. HTMLMarqueeElement covers an obsolete element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); it exists only for instanceof / constructor.name fidelity and content-attribute reflection, not for use in new content.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
behavior behavior string Reflects the content attribute verbatim.
bgColor bgcolor string Reflects the content attribute verbatim.
direction direction string Reflects the content attribute verbatim.
height height string Reflects the content attribute verbatim.
hspace hspace string Reflects the content attribute verbatim.
loop loop string Reflects the content attribute verbatim.
scrollAmount scrollamount string Reflects the content attribute verbatim.
scrollDelay scrolldelay string Reflects the content attribute verbatim.
trueSpeed truespeed boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
vspace vspace string Reflects the content attribute verbatim.
width width string Reflects the content attribute verbatim.

See also

HTMLMediaElement

HTMLMediaElement

An abstract interface — no tag creates one directly. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
crossOrigin crossorigin nullable enum Keywords: anonymous · use-credentials. Missing attribute → null; any other present value → "anonymous"; assigning null removes the attribute.
preload preload string Reflects the content attribute verbatim.
autoplay autoplay boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
loop loop boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
controls controls boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLMenuElement

HTMLMenuElement

The interface for <menu>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLMetaElement

HTMLMetaElement

The interface for <meta>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.
content content string Reflects the content attribute verbatim.
httpEquiv http-equiv string Reflects the content attribute verbatim.
charset charset string Reflects the content attribute verbatim.

See also

HTMLMeterElement

HTMLMeterElement

The interface for <meter>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
value value number, read/write Unset → 0; clamped to [min, max].
min min number, read/write Unset → 0.
max max number, read/write Unset → 1, and never below min.
low low number, read/write Unset → min; clamped to [min, max].
high high number, read/write Unset → max; clamped to [low, max].
optimum optimum number, read/write Unset → the midpoint of min and max; clamped to [min, max].

See also

HTMLModElement

HTMLModElement

The interface shared by <ins>, <del>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
cite cite string Reflects the content attribute verbatim.
dateTime datetime string Reflects the content attribute verbatim.

See also

HTMLOListElement

HTMLOListElement

The interface for <ol>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
reversed reversed boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
start start number unset → 1; negative values allowed.
type type string Reflects the content attribute verbatim.

See also

HTMLObjectElement

HTMLObjectElement

The interface for <object>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
data data string Reflects the content attribute verbatim.
type type string Reflects the content attribute verbatim.
name name string Reflects the content attribute verbatim.
width width string Reflects the content attribute verbatim.
height height string Reflects the content attribute verbatim.

See also

HTMLOptGroupElement

HTMLOptGroupElement

The interface for <optgroup>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
label label string Reflects the content attribute verbatim.

See also

HTMLOptionElement

HTMLOptionElement

The interface for <option>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
value value string Reflects the content attribute (the browser's defaultValue) — not live editing state, since the server DOM is static.
label label string Reflects the content attribute verbatim.
selected selected boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLOutputElement

HTMLOutputElement

The interface for <output>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.

See also

HTMLParagraphElement

HTMLParagraphElement

The interface for <p>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLParamElement

HTMLParamElement

The interface for <param>. Extends HTMLElementElement.

Deprecated. HTMLParamElement covers an obsolete element (WHATWG HTML §16.3 "Other elements, attributes and APIs"); it exists only for instanceof / constructor.name fidelity and content-attribute reflection, not for use in new content.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.
value value string Reflects the content attribute verbatim.

See also

HTMLPictureElement

HTMLPictureElement

The interface for <picture>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLPreElement

HTMLPreElement

The interface for <pre>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLProgressElement

HTMLProgressElement

The interface for <progress>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
value value number, read/write Unset or negative → 0; clamped to [0, max].
max max number, read/write Unset or non-positive → 1.

See also

HTMLQuoteElement

HTMLQuoteElement

The interface shared by <blockquote>, <q>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
cite cite string Reflects the content attribute verbatim.

See also

HTMLScriptElement

HTMLScriptElement

The interface for <script>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
type type string Reflects the content attribute verbatim.
defer defer boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
async async boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
noModule nomodule boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
crossOrigin crossorigin nullable enum Keywords: anonymous · use-credentials. Missing attribute → null; any other present value → "anonymous"; assigning null removes the attribute.
referrerPolicy referrerpolicy enum Keywords: "" · no-referrer · no-referrer-when-downgrade · same-origin · origin · strict-origin · origin-when-cross-origin · strict-origin-when-cross-origin · unsafe-url. Missing → ""; invalid → "".

See also

HTMLSelectElement

HTMLSelectElement

The interface for <select>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.
required required boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
multiple multiple boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLSlotElement

HTMLSlotElement

The interface for <slot>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.

See also

HTMLSourceElement

HTMLSourceElement

The interface for <source>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
type type string Reflects the content attribute verbatim.
srcset srcset string Reflects the content attribute verbatim.
sizes sizes string Reflects the content attribute verbatim.
media media string Reflects the content attribute verbatim.

See also

HTMLSpanElement

HTMLSpanElement

The interface for <span>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLStyleElement

HTMLStyleElement

The interface for <style>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
media media string Reflects the content attribute verbatim.
type type string Reflects the content attribute verbatim.

See also

HTMLTableCaptionElement

HTMLTableCaptionElement

The interface for <caption>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLTableCellElement

HTMLTableCellElement

The interface shared by <td>, <th>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
colSpan colspan number unset → 1; clamped to [1, 1000].
rowSpan rowspan number unset → 1; clamped to [0, 65534].
headers headers string Reflects the content attribute verbatim.
scope scope enum Keywords: row · col · rowgroup · colgroup. Missing → ""; invalid → "".
abbr abbr string Reflects the content attribute verbatim.

See also

HTMLTableColElement

HTMLTableColElement

The interface shared by <col>, <colgroup>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
span span number unset → 1; clamped to [1, 1000].

See also

HTMLTableElement

HTMLTableElement

The interface for <table>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLTableRowElement

HTMLTableRowElement

The interface for <tr>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLTableSectionElement

HTMLTableSectionElement

The interface shared by <thead>, <tbody>, <tfoot>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLTemplateElement

HTMLTemplateElement

The interface for <template>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLTextAreaElement

HTMLTextAreaElement

The interface for <textarea>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
name name string Reflects the content attribute verbatim.
placeholder placeholder string Reflects the content attribute verbatim.
required required boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
disabled disabled boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
readOnly readonly boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.
rows rows number unset → 2; minimum 1 (an out-of-range value falls back to the default).
cols cols number unset → 20; minimum 1 (an out-of-range value falls back to the default).
wrap wrap enum Keywords: soft · hard. Missing → "soft"; invalid → "soft".

See also

HTMLTimeElement

HTMLTimeElement

The interface for <time>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
dateTime datetime string Reflects the content attribute verbatim.

See also

HTMLTitleElement

HTMLTitleElement

The interface for <title>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLTrackElement

HTMLTrackElement

The interface for <track>. Extends HTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
src src string Reflects verbatim — no base-URL resolution.
kind kind enum Keywords: subtitles · captions · descriptions · chapters · metadata. Missing → "subtitles"; invalid → "metadata".
srclang srclang string Reflects the content attribute verbatim.
label label string Reflects the content attribute verbatim.
default default boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also

HTMLUListElement

HTMLUListElement

The interface for <ul>. Extends HTMLElementElement.

No interface-specific reflected properties — every member comes from HTMLElement and Element. Use getAttribute / setAttribute for any other attribute.

See also

HTMLVideoElement

HTMLVideoElement

The interface for <video>. Extends HTMLMediaElementHTMLElementElement.

Reflected properties

All setters are guarded and throw NoModificationAllowedError on a read-only document.

Property Attribute Type Notes
width width number unset → 0.
height height number unset → 0.
poster poster string Reflects the content attribute verbatim.
playsInline playsinline boolean (presence) Reading reflects whether the attribute is present; writing false removes it, any other value sets it present.

See also