Plate № 14 · Meta-pattern · documentation primitive
A pattern from the gf.cx specimen book
Pattern preview · live demo + tabbed code
"How could we put in real-code examples of the elements — so that we can see it, like how CodePen does it? Visual + code to the side. It's a preview pattern, for pattern library."
The problem
A pattern entry that documents interactive behaviour — a tooltip, a pulse, a hover-zone guard — earns one <pre><code> block in the prose and asks the reader to imagine what it looks like. The reader can either trust the description or open a new browser tab and rebuild it themselves. Either way, the learning loop is broken: the page tells you about the behaviour without letting you feel it.
The shape
A reusable block that pairs an isolated live demo with the source that produced it. Demo runs in an iframe sandbox so its styles never leak into the host page. Source is shown in a tabbed dark panel (HTML / CSS / JS) with a Copy button. Side-by-side at desktop, stacked at mobile.
| Piece | What it does |
|---|---|
<template data-tab="html|css|js"> | Author writes raw source inside <template> elements. data-tab names the language for the tab label + iframe assembly. |
data-external-css / data-external-js | Comma-separated URLs of external assets to load inside the iframe head (e.g. assets.gf.cx/tooltip/tooltip.css). Lets a demo depend on the portfolio's primitive CSS without redefining it. |
pattern-preview.js assembles srcdoc | Reads each template, dedents the source, builds a single <iframe srcdoc="…"> with external assets in <head> + inline code in <body>. Iframe is sandbox="allow-scripts allow-popups". |
| Tabs + Copy button | Click a tab to switch the source pane (HTML default). Copy button copies the currently-shown source to clipboard with a 1.6s "Copied ✓" confirmation. |
The element, in-page
This block is itself a pattern-preview — the primitive documenting itself. It demos the simplest possible interactive case: a button that increments a counter. Inspect the three tabs to see how HTML / CSS / JS compose into the live iframe on the left. Every other pattern entry on this site uses exactly this block for its own live demos.
The trap — host-page style leak
The naive version inlines the demo HTML directly into the patterns.gf.cx body. The host page's serif fonts, link styles, code styles, and CSS variables apply to the demo — the demo no longer looks like the surface where it'll actually run, and any aggressive demo CSS (e.g. body { background: black }) leaks back into the host page. The iframe sandbox is non-negotiable: each demo gets its own document scope, its own root element, its own stylesheet origin.
Why srcdoc over a separate file
- Single source of truth. The same code text feeds the tabbed view AND the iframe — no risk of the displayed source drifting from the running demo.
- No HTTP round-trip per pattern. Demos are inline in the page; no
/demos/<slug>.htmlfile to maintain. Adding a new pattern is one<div>. - External assets still load. Absolute URLs in
data-external-css/data-external-jsresolve normally inside the srcdoc. Relative URLs do not — that's the one constraint.
Where it applies
- Any pattern entry that describes interactive or visual behaviour the reader can't predict from the code alone (tooltips, hover states, animations, focus management, micro-gestures)
- Onboarding docs that need a "see it work first, then read the why" rhythm
- NOT for patterns that are purely conceptual (deploy rituals, naming conventions) — the demo would be performative noise
A pattern library that only describes its patterns is a glossary. A pattern library that lets you feel them is a workbook.
Reusable elements
/assets/pattern-preview.js— ~120 lines, no dependencies. Reads each<template data-tab>viat.innerHTML, dedents the source, builds the srcdoc, wires tabs and Copy button./assets/pattern-preview.css— CodePen-style two-column layout (live demo left, dark code pane right); stacks vertically below 800 px. Also ships the sharedul.reuse-listanddl.pattern-refgold-standard closers.<template data-tab="html|css|js">authoring contract — raw source inside<template>elements, one per language. Content is parsed as HTML by the browser, fed simultaneously to the live srcdoc and the tabbed code pane. Write real<— the template element handles it.data-external-css/data-external-js— comma-separated absolute URLs injected into the iframe<head>. Lets a demo pull in portfolio primitives (tooltip CSS, cards CSS) without redefining them inline.
Reference
- Source
- Dan, 2026-06-08 · "How could we put in real-code examples of the elements — so that we can see it, like how CodePen does it?" Split from
patterns.gf.cx/index.html2026-06-22. - In use / example
- patterns.gf.cx/timeline-overlap-zone-card/ — the canonical in-use entry. Its gate-hero + UTC timeline demo runs inside a
pattern-previewblock. Copy it as a starting template for any new pattern entry that needs a live demo. - Reusable elements
/assets/pattern-preview.js·/assets/pattern-preview.css·<template data-tab>authoring contract ·data-external-css/data-external-jsattributes.- Origin
- Every pattern that shows interactive behaviour needs a "see it first, read the why second" loop. A static
<pre><code>block breaks that loop. This primitive closes it without requiring a separate file or a third-party embed.