Skip to content

12. Events & Interactive Elements

This chapter specifies two categories of custom element whose behavior is unusual: event-only elements, which produce no DOM, and interactive elements, which preserve state across re-renders.

12.1 Event-only elements

An event-only element is a custom element whose appearance in source MUST NOT produce any DOM node. Instead, the element's parse MUST emit an event record to the implementation's event channel (if present).

12.1.1 Source form

Event-only elements use self-closing tag form:

<event-name attr1="value1" attr2="value2"/>

The closing slash is REQUIRED in source.

12.1.2 Event record

An event record has the shape:

Event {
  type: string,           // tag name
  attributes: Attr[],     // filtered per §10.3.3
  source: { line, column } // position in source
}

Events MUST be emitted in source order. Implementations MAY expose events via a callback, a stream, or a queue; none is normative.

12.1.3 Event-only tag whitelist

Core specification reserves three event-only tags:

  • <progress value="..."/> — progress updates. value MUST be a decimal 0.0–1.0.
  • <status code="..." message="..."/> — status updates. code SHOULD be a short identifier.
  • <milestone name="..."/> — named checkpoints.

Extensions MAY register additional event-only tags per §8.2.

12.1.4 No DOM rule

A conforming implementation's rendered DOM for an event-only element MUST contain zero nodes for that element — no wrapper, no comment, no zero-width space. Diff comparisons MUST agree.

12.2 Interactive elements

An interactive element is a custom element whose DOM subtree holds mutable state (input values, toggle positions, counters) that MUST survive re-renders caused by subsequent chunks.

12.2.1 Source form

Interactive elements use standard open/close tag form:

<md-button label="Click me">Content</md-button>
<md-toggle state="off"/>
<md-input placeholder="..."/>

12.2.2 State preservation

On re-render of a region containing an interactive element:

REQ-INT-1. If the element's tag name, id attribute (if any), and source position match between the old and new AST, the renderer MUST reuse the existing DOM node rather than creating a new one.

REQ-INT-2. The element's internal state (DOM state not expressed in MdFlow attributes — e.g., focus, selection, toggle state, form values) MUST NOT be reset by the re-render.

REQ-INT-3. Attributes present in both the old and new AST MUST be updated by writing the new value; attributes only in the old AST MUST be removed; attributes only in the new AST MUST be added.

12.2.3 Identity

An interactive element's identity for reuse purposes is determined in order of preference:

  1. A stable id attribute in source.
  2. A stable data-key attribute in source.
  3. The element's source slice start position within its parent block.

If none match, the element is considered new and a fresh DOM node is created.

12.2.4 Reserved attributes

The attributes data-mdflow-* are reserved for implementation use (§3.5). Interactive-element authors MUST NOT declare them.

12.3 Event handlers on interactive elements

Interactive elements MAY expose behavior via JavaScript attached to their DOM nodes outside the MdFlow pipeline — e.g., by the host application using addEventListener. MdFlow source MUST NOT emit any on* attribute per §10.2.

Extensions MAY define synthetic event attributes that are translated by the implementation into programmatic listeners at render time; the mechanism for such translation is specified in the extension, not in the core.

12.4 Test vectors

The conformance suite includes interaction-state vectors (§13.5) that:

  • re-render a region containing <md-toggle/> and verify the toggle state persists,
  • re-render with modified surrounding source and verify the interactive DOM node is reused (by object identity, using data-mdflow-token-id or equivalent),
  • verify event-only elements produce no DOM.

12.5 Accessibility

Interactive elements SHOULD carry appropriate ARIA attributes and MUST NOT suppress default keyboard interaction expected for their semantic role. The core specification defers accessibility details to individual extension specifications.