Skip to content

Core Concepts ​

Generative DOM is built around a few key ideas. Understanding them will help you use the library effectively and write your own plugins.

Streaming ​

Generative DOM is designed for input that arrives incrementally. The push() method accepts arbitrary chunks of text -- a single character, a partial word, an entire paragraph. The parser handles chunks that split markdown at any point, including mid-syntax (**bol + d**), mid-escape (\ + *), and mid-link ([text](ur + l)).

When the tokenizer encounters ambiguous trailing content, it preserves the unconsumed portion in the buffer. The next push() appends new content and tokenization retries from where it left off.

Plugins ​

Generative DOM's core knows nothing about markdown. All syntax recognition and rendering is handled by plugins. The core is a plugin host that provides:

  • A buffer and tokenizer loop
  • An object pool for DOM element reuse
  • A scheduler for batched rendering
  • An event system for inter-plugin communication

Each plugin declares a priority number that determines matching order. Lower numbers are matched first. Recommended ranges:

RangePurpose
0--99Custom syntax (matched first)
100--199Block-level markdown (headings, code, lists, quotes)
200--299Inline markdown (bold, italic, strikethrough)
300+Fallback (paragraphs, plain text)

When multiple plugins have the same priority, registration order breaks the tie.

The Rendering Pipeline ​

Input chunks --> Buffer --> Tokenizer --> Parser --> AST diff --> Renderer --> DOM
                  ^                                                |
                  +---- rAF + debounce scheduling -----------------+
  1. Buffer: push() appends text to an internal buffer and marks it dirty.
  2. Tokenizer: Iterates plugins by priority. The first plugin to return a match wins. Consumes matched characters and produces a Token.
  3. Parser: Builds a flat AST (array of block tokens, each may contain inline tokens). On each render cycle, it diffs against the previous AST.
  4. Renderer: Only updates DOM nodes for changed, new, or removed tokens. Uses the object pool for element recycling.
  5. Scheduler: push() does not render immediately. A requestAnimationFrame loop checks the dirty flag, respects debounceMs, and triggers a parse-and-render cycle.

Tokens ​

A Token is the intermediate representation between parsing and rendering:

ts
interface Token {
  type: string;           // Identifies which plugin handles rendering
  raw: string;            // Original matched markdown
  children?: Token[];     // Nested tokens (e.g., list items)
  content?: string;       // Inner text content
  meta?: Record<string, unknown>; // Plugin-specific data
}

Block-level plugins produce tokens via matchBlock(). Inline-level plugins produce tokens via matchInline(). The core routes each token to the plugin whose type matches for rendering.

Object Pool ​

Generative DOM recycles DOM elements to avoid garbage collection pressure during rapid streaming. When a token is removed from the AST, its DOM element is returned to the pool. When a new token of the same tag is needed, the pool provides a pre-existing element instead of creating one.

ts
interface ObjectPool {
  acquire(tag: string): HTMLElement;
  release(element: HTMLElement): void;
  drain(): void;
  stats(): { pooled: number; active: number; created: number; reused: number };
}

Plugins access the pool through the RenderContext provided to their render() method.

Events ​

Plugins can emit events through the plugin context. Events are namespaced by plugin name automatically:

ts
// Inside a plugin:
ctx.emit('progress', { value: 35 });
// Subscribers receive it as "pluginName:progress"

// Subscribing from application code:
md.on('events:progress', (data) => {
  console.log(data); // { value: 35 }
});

Events are dispatched synchronously. If a listener throws, other listeners still execute.

Security Model ​

Generative DOM enforces security at the architecture level:

  • All DOM construction uses document.createElement and document.createTextNode -- never innerHTML
  • Link href values are whitelisted to https:, http:, and mailto: protocols
  • Image src values are whitelisted to https: and http:
  • No on* event handler attributes are allowed on any element
  • Custom element attribute whitelists are enforced by the core

See the Security Guide for details.

Next: Streaming Guide