Grid Identity

HTML declares structure, CSS assigns layout. Semantic elements auto-register to grid areas based on their type — no classes needed.

The Concept

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.

Zen Garden Principle: HTML declares structure. CSS assigns layout. JavaScript handles behavior. Each concern stays in its proper layer.

Three Tiers

Grid identity works at three levels, each scoped to a different container:

Tier 1: Page

data-page-layout

Body-level structure. Areas: body-header, body-nav, body-main, body-aside, body-footer

Tier 2: Main

main[data-layout]

Nested layout within content area. Areas: main-header, main-nav, main-article, main-aside, main-footer

Tier 3: Component

data-layout="regions"

Generalized structure on any element. Areas: header, content, footer

Page-Level Identity

Apply data-page-layout to the <body> element. Direct semantic children are auto-assigned to grid areas based on their element type.

Available Templates

Template Token Description
stack--tpl-stackSingle column, mobile-first
sidebar-left--tpl-sidebar-leftTwo-column with left navigation
sidebar-right--tpl-sidebar-rightTwo-column with right sidebar
holy-grail--tpl-holy-grailThree-column classic layout
app-shell--tpl-app-shellVertical nav bar for apps
dashboard--tpl-dashboardAdmin panel with sticky nav
article--tpl-articleCentered content for reading
landing--tpl-landingMarketing page with named sections

Grid Identity Mapping

Element Grid Area
<header>body-header
<nav>body-nav
<main>body-main
<aside>body-aside
<footer>body-footer

Example

<body data-page-layout="sidebar-left"> <header>Site header</header> <nav>Navigation</nav> <main>Content</main> <footer>Site footer</footer> </body>

Content-Aware Adaptation

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 column
  • sidebar-right without <aside> → single column
  • holy-grail without <aside> → two columns
  • holy-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).

View the page layouts demo →

Named Area Overrides

Use data-layout-area to explicitly assign any element to a named grid area. This overrides the automatic identity assignment.

Value Use Case
heroHero section on landing pages
featureFeature showcase section
ctaCall-to-action section
sidebarGeneric sidebar area
contentMain content area
bannerBanner or announcement
tocTable of contents

Landing Page Example

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>
When to use explicit vs auto: Use auto identity (the default) for standard page structure. Use data-layout-area when you need sections that do not map to standard semantic elements, or when using the landing template.

View the landing page demo →

Main-Level Identity

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.

Main-Level Grid Areas

Element Grid Area
<header>main-header
<nav>main-nav
<article>main-article
<section>main-section
<aside>main-aside
<footer>main-footer

Available Main-Level Templates

Template Grid Use Case
sidebar-leftmain-nav | main-articleDocumentation with sub-navigation
sidebar-rightmain-article | main-asideArticle 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.

Component-Level Regions

Two new layout types extend grid identity down to individual components.

Regions

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 childcontent (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>

Grid of Region Cards

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>

View the regions demo →

Media Object

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 childcontent
<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-reverseContent on left, figure on right
data-layout-alignVertical alignment: start, center, end, stretch
data-layout-gapGap between figure and content

Media objects stack vertically in containers narrower than 25rem (via container query).

View the media object demo →

Composing Tiers

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:

  • Tier 1data-page-layout="sidebar-left" on body places the header, nav, main, and footer into page-level grid areas.
  • Tier 2data-layout="sidebar-right" on main creates a secondary sidebar for the table of contents, using main-article and main-aside areas.
  • Tier 3data-layout="regions" on article auto-places its header, section, and footer into component-level areas.
No collisions: Each tier uses namespaced area names (body-*, main-*, header/content/footer). They compose freely without conflict.

View the three-tier nesting demo →

Quick Reference

Utilities

Attribute Effect
data-layout-stickySticky positioning for header, nav, or aside
data-layout-bleedSpan all grid columns (full-width)
data-layout-nowrapPrevent responsive collapse to stack
data-sidebar="collapsed"Use collapsed sidebar width (64px)
data-sidebar="hidden"Hide the sidebar nav entirely
data-layout-areaExplicit grid area override

Named Containers

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.

Related Pages

Semantic Layouts

Component-level data-layout attributes.

Attributes Reference

Complete data-layout API documentation.

Shell Patterns

Page layout patterns in practice.

Demos

Interactive layout demonstrations.