Appearance
custom-elements
Parses custom HTML-like elements from the markdown stream and renders them as actual Web Components. Demonstrates the plugin system handling non-markdown syntax.
Details
| Property | Value |
|---|---|
| Name | custom-elements |
| Priority | 50 |
| Type | Block |
| Factory | customElements(options?) |
Syntax
The plugin recognizes two patterns in the stream:
Self-closing:
markdown
<md-clock />
<md-counter start="5" />Content-bearing:
markdown
<md-plot color="blue">1,2,4,7,3</md-plot>Only whitelisted tag names are processed. Unknown tags are treated as plain text.
Built-in Custom Elements
<md-clock />
Displays a live ticking clock. Self-contained with no attributes. Uses setInterval internally, cleaned up on disconnectedCallback.
markdown
<md-clock /><md-plot>
Takes comma-separated numbers as content and renders an inline SVG bar chart.
markdown
<md-plot color="blue" width="200" height="100">1,2,4,7,3</md-plot>| Attribute | Type | Default | Description |
|---|---|---|---|
width | number | 200 | Chart width in pixels |
height | number | 100 | Chart height in pixels |
color | string | "steelblue" | Bar fill color |
<md-counter>
Displays a number with increment and decrement buttons.
markdown
<md-counter start="5" min="0" max="10" />| Attribute | Type | Default | Description |
|---|---|---|---|
start | number | 0 | Initial value |
min | number | none | Minimum value |
max | number | none | Maximum value |
API
ts
import { customElements } from '@generative-dom/plugins';
const plugin = customElements({
allowedTags: ['md-clock', 'md-plot', 'md-counter'],
});Options
| Option | Type | Default | Description |
|---|---|---|---|
allowedTags | string[] | All built-in tags | Whitelist of allowed custom element tag names |
Security
- Only whitelisted tags are parsed.
<evil-script />renders as plain text. - Event handler attributes (
onclick,onerror, etc.) are stripped. - The
styleattribute is blocked if it containsurl()orexpression(). - Inner content for custom elements is raw -- markdown inside is not parsed.
Edge Cases
- Malformed tags:
<clock,<clock / >,< clock/>are treated as plain text - Unknown tags:
<evil-script />is rendered as plain text - Special characters in attributes:
<md-plot color="red&blue">-- attributes are set viasetAttribute, so special characters are safe - Self-closing vs. content-bearing mismatch: The parser handles both forms for any registered element
- Stream splits mid-tag:
<md-cl+ock />-- the buffer waits for the complete tag - Markdown in content:
<md-plot>**not bold**</md-plot>-- inner content is treated as raw text, not parsed as markdown
Rendering
Each custom element is registered as a real Web Component via customElements.define(). The plugin creates instances of these components and sets their attributes and content from the parsed stream.