Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
← All tutorials · ~10 minutes · Layer focus: typography & reading
Build a long-form article with prose typography, tag pills, a collapsible "further reading" section, and a sticky table of contents — everything you need for a readable blog template.
An article is an article. Native HTML already has the elements we need: <article>, <header>, <blockquote>, <footer>. Start with the content.
<article> <header> <p><small>Engineering · 6 min read</small></p> <h1>Shipping a design system without a framework</h1> <p><small>By Jane Doe · April 20, 2026</small></p> </header> <p>Frameworks aren't the only way to scale...</p> <blockquote> <p>"The most durable UI is the one that works before any JavaScript runs."</p> </blockquote> <h2>Three layers, three promises</h2> <p>Think about a web page the way the platform thinks about it...</p> <ul> <li>Semantic elements do the heavy lifting</li> <li>Design tokens keep colors and spacing consistent</li> <li>Web components fill the gaps</li> </ul> <footer> <button type="button">Share</button> <button type="button">Subscribe</button> </footer></article>
Long text needs a measure — a constrained line length that keeps eyes moving horizontally without getting lost. That's exactly what data-layout-max="prose" is for.
<main data-layout="center" data-layout-max="prose" data-layout-gap="m"> <article data-layout="stack" data-layout-gap="m"> <header data-layout="stack" data-layout-gap="xs"> <p><small>Engineering · 6 min read</small></p> <h1>Shipping a design system without a framework</h1> <p><small>By Jane Doe · April 20, 2026</small></p> </header> <!-- paragraphs, blockquote, lists… --> <footer data-layout="cluster" data-layout-gap="s"> <button type="button">Share</button> <button type="button" class="secondary">Subscribe</button> </footer> </article></main>
Values for data-layout-max on a center region: narrow, normal, wide, and prose. prose caps the line at 65 characters — the width research suggests for comfortable reading.
A few places call for a custom element: the tag pills in the header, and a clear "callout" surface for a key takeaway. <layout-badge> gives you the pill shape, and <layout-card> gives you the callout.
<header data-layout="stack" data-layout-gap="xs"> <nav data-layout="cluster" data-layout-gap="xs" aria-label="Tags"> <layout-badge data-variant="info">Engineering</layout-badge> <layout-badge data-variant="info">Platform</layout-badge> <layout-badge>6 min read</layout-badge> </nav> <h1>Shipping a design system without a framework</h1> <p><small>By Jane Doe · April 20, 2026</small></p></header> <!-- later in the article… --> <layout-card data-variant="ghost" data-padding="l"> <p><strong>Key takeaway.</strong> Going framework-free doesn't mean giving up structure. You still get tokens, themes, and layout primitives — just expressed as plain HTML.</p></layout-card>
Still no JavaScript. The badges and card are pure CSS custom elements.
Two genuine-JS wins on a long article: a clickable table of contents that highlights the current section as you scroll, and a collapsible "further reading" group that saves vertical space. The first is <page-toc>, the second is a native <details> grouped by <accordion-wc>.
<page-toc scope="article" levels="h2" title="On this page"></page-toc>
<page-toc> scans the article for headings, renders anchored links, and updates the active link as the reader scrolls. Without JavaScript it renders nothing — so the reader never sees a broken widget.
<accordion-wc single> <details name="reading"> <summary>Further reading</summary> <ul> <li><a href="/docs/concepts/">Progressive enhancement in depth</a></li> <li><a href="/docs/semantic-layouts/">Semantic layouts with data-layout</a></li> <li><a href="/docs/themes/">Theme system and token architecture</a></li> </ul> </details> <details name="reading"> <summary>Code samples</summary> <ul> <li><a href="/docs/snippets/html/hero-section/">Hero section snippets</a></li> <li><a href="/docs/patterns/forms/contact/">Contact form pattern</a></li> </ul> </details></accordion-wc>
<accordion-wc> enhances native <details name="…"> groups with keyboard navigation and smoother transitions. If JavaScript fails, the browser's built-in exclusive-disclosure behavior still works — that's why we use name="" on the <details> elements.
data-layout-max="prose" constrains line length to a comfortable reading width.<layout-badge> gives you pill-shaped tags without <span class=""> everywhere.<page-toc> generates a scroll-aware table of contents with zero config.<accordion-wc> enhances native <details name="…"> — and gracefully falls back to it.