Composition Patterns — Chrome vs. Content
Every page-edge primitive in WireKit (brand-bar, header, footer, hero, cta, section) sits on a single composition axis: chrome vs. content.
- Chrome = the bar's visual frame (background color, top/bottom border, sticky behavior, drop shadow). Typically spans viewport edge-to-edge so the visual frame is uninterrupted across screen widths.
- Content = the brand logo, navigation links, action buttons, headline copy. Typically centerd inside a max-width column (e.g.
max-w-[var(--size-wk-container-xl)]) so the eye doesn't have to track ultra-wide line lengths.
When chrome and content live on the same X-coordinate spine, the page feels intentional. When they diverge, the brand bar's logo "floats" relative to the page heading below it — a small misalignment that compounds visually across the full page height.
This page documents the contract WireKit uses to keep them aligned, and shows which primitive exposes which API for opting into either mode.
The Two Modes
Edge-to-edge content (default for most primitives)
Both chrome and content span viewport-edge to viewport-edge. The brand-bar's logo sits at the bar's --padding-wk-x-lg inset; the bar's bottom border crosses the full viewport width.
<x-wirekit::brand-bar sticky>
<x-slot:brand><x-wirekit::brand>Acme</x-slot:brand></x-slot:brand>
<x-slot:actions>
<x-wirekit::button>Sign in</x-wirekit::button>
</x-slot:actions>
</x-wirekit::brand-bar>
<x-wirekit::hero>
<x-slot:title>Welcome to Acme</x-slot:title>
</x-wirekit::hero>
This works when:
- Your page below the bar ALSO renders edge-to-edge (no inner container).
- OR the bar's brand position naturally aligns with the body's left content edge by virtue of matching padding values.
Container-wrapped content (opt-in via container prop)
Chrome stays edge-to-edge (background, border, sticky behavior), but content lives inside a max-width column that aligns with your page's body container.
<x-wirekit::brand-bar sticky container max="xl">
<x-slot:brand><x-wirekit::brand>Acme</x-slot:brand></x-slot:brand>
<x-slot:actions>
<x-wirekit::button>Sign in</x-wirekit::button>
</x-slot:actions>
</x-wirekit::brand-bar>
<x-wirekit::container max="xl">
<x-wirekit::hero>
<x-slot:title>Welcome to Acme</x-slot:title>
</x-wirekit::hero>
</x-wirekit::container>
The brand-bar's outer <header> keeps the sticky behavior + the bottom border + the full-width background. The inner flex-row carries the max-w-[var(--size-wk-container-xl)] + mx-auto so the logo sits on the same content-edge X-coordinate as the body container below.
Per-primitive Participation
| Primitive | Edge-to-edge default | container prop |
max prop |
Internal hardcoded max |
|---|---|---|---|---|
<x-wirekit::brand-bar> |
yes | yes | yes (sm/md/lg/xl/2xl/full, default xl) |
none |
<x-wirekit::header> |
yes | yes (boolean only) | no — hardcoded 2xl when container=true |
2xl (legacy) |
<x-wirekit::footer> |
yes | n/a (footer ALWAYS has an inner wrapper) | yes (sm/md/lg/xl/2xl/full, default xl) |
none |
<x-wirekit::hero> |
n/a | n/a (hero ALWAYS uses inner max-width content wrapper, hardcoded xl) |
no | xl (intentional — hero copy needs the focus column) |
<x-wirekit::cta> |
n/a | n/a | no | md (narrow conversion-focused) |
<x-wirekit::section> |
yes (slot is raw) | no | no | n/a — developer applies their own <x-wirekit::container> inside |
The variance reflects each primitive's primary use case: hero and cta benefit from narrow content columns regardless of viewport, whereas brand-bar and footer are flexible chrome that should match whatever the body container width is.
Worked Example — Landing Page Skeleton
<!DOCTYPE html>
<html>
<head>
@vite('resources/css/app.css')
@wirekitStyles
</head>
<body>
<x-wirekit::brand-bar sticky container max="xl">
<x-slot:brand><x-wirekit::brand>Acme</x-slot:brand></x-slot:brand>
<x-slot:actions>
<x-wirekit::button>Sign in</x-wirekit::button>
</x-slot:actions>
</x-wirekit::brand-bar>
<x-wirekit::container max="xl">
<x-wirekit::hero variant="dark" gradient size="lg">
<x-slot:title>Build faster.</x-slot:title>
<x-slot:lede>Acme cuts your time-to-deploy in half.</x-slot:lede>
<x-slot:actions>
<x-wirekit::button intent="neutral" surface="filled">Get started</x-wirekit::button>
</x-slot:actions>
</x-wirekit::hero>
<x-wirekit::feature-grid cols="1 sm:2 lg:3" stagger>
<x-wirekit::feature animateIn="slide-up" title="Fast">…</x-wirekit::feature>
<x-wirekit::feature animateIn="slide-up" title="Reliable">…</x-wirekit::feature>
<x-wirekit::feature animateIn="slide-up" title="Secure">…</x-wirekit::feature>
</x-wirekit::feature-grid>
<x-wirekit::cta variant="accent" size="md">
<x-slot:title>Ship faster today.</x-slot:title>
<x-slot:actions>
<x-wirekit::button intent="neutral" surface="filled">Start free trial</x-wirekit::button>
</x-slot:actions>
</x-wirekit::cta>
</x-wirekit::container>
<x-wirekit::footer max="xl">
<x-slot:brand>Acme · © 2026</x-slot:brand>
<x-slot:legal>
<a href="/privacy">Privacy</a>
<a href="/terms">Terms</a>
</x-slot:legal>
</x-wirekit::footer>
@wirekitScripts
</body>
</html>
All five primitives (brand-bar / hero / feature-grid / cta / footer) share the same xl content-edge spine. The brand logo, hero headline, cta title, and footer legal row all sit on the same vertical X-coordinate. The brand-bar's background AND the footer's background extend edge-to-edge across the viewport (chrome stays separated from content geometry).
Decision Tree
"My page has edge-to-edge content (no inner container)"
→ Use the primitives with their defaults. Don't opt into container=true or set max.
"My page has container-wrapped content"
→ Pass container max="xl" (or whichever max-value matches your body) to brand-bar.
→ Pass max="xl" to footer.
→ Hero and cta have their own intentional internal max-widths — leave alone.
→ Wrap section content in your own <x-wirekit::container> as needed.
"My page mixes edge-to-edge sections (e.g. full-bleed image carousel) with container-wrapped sections"
→ The brand-bar typically stays at the page top regardless of section style.
→ Per-section, use <x-wirekit::container> only around the container-wrapped ones; let the edge-to-edge ones render outside.