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.
HTML declares structure, CSS assigns layout. Semantic elements auto-register to grid areas based on their type — no classes needed.
VB's grid identity system implements the CSS Zen Garden principle: the same semantic HTML transforms through pure CSS. Write <header>, <nav>, <main>, <aside>, and <footer>, and the layout assigns them to grid areas automatically.
Grid identity works at three levels, each scoped to a different container:
data-page-layout
Body-level structure. Areas: body-header, body-nav, body-main, body-aside, body-footer
main[data-layout]
Nested layout within content area. Areas: main-header, main-nav, main-article, main-aside, main-footer
data-layout="regions"
Generalized structure on any element. Areas: header, content, footer
Apply data-page-layout to the <body> element. Direct semantic children are auto-assigned to grid areas based on their element type.
| Template | Token | Description |
|---|---|---|
stack | --tpl-stack | Single column, mobile-first |
sidebar-left | --tpl-sidebar-left | Two-column with left navigation |
sidebar-right | --tpl-sidebar-right | Two-column with right sidebar |
holy-grail | --tpl-holy-grail | Three-column classic layout |
app-shell | --tpl-app-shell | Vertical nav bar for apps |
dashboard | --tpl-dashboard | Admin panel with sticky nav |
article | --tpl-article | Centered content for reading |
landing | --tpl-landing | Marketing page with named sections |
| Element | Grid Area |
|---|---|
<header> | body-header |
<nav> | body-nav |
<main> | body-main |
<aside> | body-aside |
<footer> | body-footer |
<body data-page-layout="sidebar-left"> <header>Site header</header> <nav>Navigation</nav> <main>Content</main> <footer>Site footer</footer></body>
Layouts automatically adapt when elements are absent. CSS :has() selectors detect what children are present and adjust the grid template accordingly.
sidebar-left without <nav> → single columnsidebar-right without <aside> → single columnholy-grail without <aside> → two columnsholy-grail without both → single column<!-- No nav present → layout adapts to single column automatically --><body data-page-layout="sidebar-left"> <header>Site header</header> <!-- <nav> removed → :has() adapts columns --> <main>Full-width content</main> <footer>Footer</footer></body>
All page layouts collapse to stack on viewports narrower than 768px (unless data-layout-nowrap is set).
Use data-layout-area to explicitly assign any element to a named grid area. This overrides the automatic identity assignment.
| Value | Use Case |
|---|---|
hero | Hero section on landing pages |
feature | Feature showcase section |
cta | Call-to-action section |
sidebar | Generic sidebar area |
content | Main content area |
banner | Banner or announcement |
toc | Table of contents |
The landing page template defines areas for hero, feature, and cta. Use data-layout-area to assign sections to these areas.
<body data-page-layout="landing" data-layout-gap="none"> <header>...</header> <section data-layout-area="hero">Hero content</section> <section data-layout-area="feature">Features grid</section> <section data-layout-area="cta">Call to action</section> <footer>...</footer></body>
data-layout-area when you need sections that do not map to standard semantic elements, or when using the landing template.
The <main> element can have its own data-layout to create a second tier of grid identity. Children of main[data-layout] auto-register to main-* areas.
| Element | Grid Area |
|---|---|
<header> | main-header |
<nav> | main-nav |
<article> | main-article |
<section> | main-section |
<aside> | main-aside |
<footer> | main-footer |
| Template | Grid | Use Case |
|---|---|---|
sidebar-left | main-nav | main-article | Documentation with sub-navigation |
sidebar-right | main-article | main-aside | Article with table of contents |
<main data-layout="sidebar-right"> <article> <!-- auto → main-article area --> <h1>Page Content</h1> <p>Article body...</p> </article> <aside> <!-- auto → main-aside area --> <nav>Table of contents</nav> </aside></main>
Main-level templates also support :has() adaptation: if the nav or aside is absent, the layout falls back to a single column.
Two new layout types extend grid identity down to individual components.
data-layout="regions" creates a header / content / footer grid on any element. Semantic children auto-place without explicit attributes.
| Element | Grid Area |
|---|---|
<header> or [slot="header"] | header |
<section> or [slot="content"] | content |
<footer> or [slot="footer"] | footer |
| Any other child | content (implicit) |
<article data-layout="regions" data-layout-gap="m"> <header>Card Title</header> <!-- auto → header area --> <section><p>Content...</p></section> <!-- auto → content area --> <footer>Updated 2h ago</footer> <!-- auto → footer area --></article>
The big win: combine data-layout="grid" with data-layout="regions" articles for card lists where each card auto-structures itself.
<div data-layout="grid" data-layout-min="15rem" data-layout-gap="m"> <article data-layout="regions" data-layout-gap="s"> <header>Performance</header> <section><p>Optimized for speed.</p></section> <footer>Core feature</footer> </article> <article data-layout="regions" data-layout-gap="s"> <header>Accessibility</header> <section><p>WCAG 2.1 AA compliant.</p></section> <footer>Built-in</footer> </article></div>
data-layout="media" places a figure and content side by side — the most common component pattern on the web.
| Element | Grid Area |
|---|---|
<figure>, <img>, <picture>, <video>, or [slot="figure"] | figure |
| Any other child | content |
<div data-layout="media" data-layout-gap="m"> <img src="avatar.jpg" alt="" width="48" height="48"> <div> <strong>Jane Doe</strong> <p>Published a new article about grid identity.</p> </div></div>
| Modifier | Effect |
|---|---|
data-layout-reverse | Content on left, figure on right |
data-layout-align | Vertical alignment: start, center, end, stretch |
data-layout-gap | Gap between figure and content |
Media objects stack vertically in containers narrower than 25rem (via container query).
The full power of grid identity appears when you nest all three tiers. Each tier is scoped to its own container, so area names never collide.
<body data-page-layout="sidebar-left"> <!-- Tier 1: page --> <header>Site Header</header> <nav>Primary Navigation</nav> <main data-layout="sidebar-right"> <!-- Tier 2: main --> <article data-layout="regions" data-layout-gap="l"> <!-- Tier 3: component --> <header><h1>Article Title</h1></header> <section><p>Article body...</p></section> <footer>Published Jan 2025</footer> </article> <aside><nav>Table of Contents</nav></aside> </main> <footer>Site Footer</footer></body>
In this example:
data-page-layout="sidebar-left" on body places the header, nav, main, and footer into page-level grid areas.data-layout="sidebar-right" on main creates a secondary sidebar for the table of contents, using main-article and main-aside areas.data-layout="regions" on article auto-places its header, section, and footer into component-level areas.body-*, main-*, header/content/footer). They compose freely without conflict.
| Attribute | Effect |
|---|---|
data-layout-sticky | Sticky positioning for header, nav, or aside |
data-layout-bleed | Span all grid columns (full-width) |
data-layout-nowrap | Prevent responsive collapse to stack |
data-sidebar="collapsed" | Use collapsed sidebar width (64px) |
data-sidebar="hidden" | Hide the sidebar nav entirely |
data-layout-area | Explicit grid area override |
Page layout regions have named containers for targeted @container queries. This lets component authors write precision queries that target a specific region rather than the nearest anonymous container.
| Context | Element | Container Name |
|---|---|---|
data-page-layout | <main> | region-main |
data-page-layout | <nav> | region-nav |
data-page-layout | <aside> | region-aside |
main[data-layout="sidebar-left"] | <nav> | region-main-nav |
main[data-layout="sidebar-left"] | <article> | region-main-content |
main[data-layout="sidebar-right"] | <article> | region-main-content |
main[data-layout="sidebar-right"] | <aside> | region-main-aside |
Example: adapt typography when the main content area is narrow:
@container region-main (width < 40rem) { .article-grid { grid-template-columns: 1fr; }}
For non-semantic elements that need containment, use the data-container attribute:
<div data-container="card"> <!-- Named container (container-name: card) --> <p>Content that responds to container width</p></div>
Available presets: card, panel, media. Use the boolean form data-container (no value) for anonymous containment.
Component-level data-layout attributes.
Complete data-layout API documentation.
Page layout patterns in practice.
Interactive layout demonstrations.