Grid Layout
CSS Grid provides two-dimensional control over both rows and columns. The Elements grid system implements CSS Grid through the nve-layout API to simplify complex layout creation.
Understanding Grid Layout
Grid layout creates structured, magazine-style layouts where precise placement and alignment matter. Unlike flexbox which is primarily one-dimensional, grid provides control over both dimensions simultaneously.
The Elements grid system uses a 12-column layout, a standard approach that provides flexibility for common design patterns.
When to Use Grid
Choose grid layout when you need:
- Multi-column layouts: Dashboards, card galleries, product listings
- Precise alignment: Forms with labels and inputs, data tables
- Complex page structures: Magazine layouts, image galleries with captions
- Responsive design: Layouts that reflow based on available space
- Overlapping elements: Layered designs with precise positioning
Grid vs Flexbox: use grid when you need to control both rows and columns. Use flexbox for one-dimensional layouts (either row or column). You can combine both systems—use grid for page structure and flexbox for component internals.
Basic Grid Setup
Set nve-layout="grid" on a container element and control child element sizing through either:
- Parent-controlled sizing with
span-items:... (all children same width) - Child-controlled sizing with individual
span:... values (flexible widths)
<!-- Parent controls all children to span 4 columns (3 per row) -->
<section nve-layout="grid gap:md span-items:4">
<nve-card>Card 1</nve-card>
<nve-card>Card 2</nve-card>
<nve-card>Card 3</nve-card>
<nve-card>Card 4</nve-card>
</section>
<!-- Children control their own spans for varied layouts -->
<section nve-layout="grid gap:md">
<nve-card nve-layout="span:8">Wide content</nve-card>
<nve-card nve-layout="span:4">Sidebar</nve-card>
<nve-card nve-layout="span:6">Half width</nve-card>
<nve-card nve-layout="span:6">Half width</nve-card>
</section>
<!-- Parent controls all children to span 4 columns (3 per row) -->
<section nve-layout="grid gap:md span-items:4">
<nve-card>Card 1</nve-card>
<nve-card>Card 2</nve-card>
<nve-card>Card 3</nve-card>
<nve-card>Card 4</nve-card>
</section>
<!-- Children control their own spans for varied layouts -->
<section nve-layout="grid gap:md">
<nve-card nve-layout="span:8">Wide content</nve-card>
<nve-card nve-layout="span:4">Sidebar</nve-card>
<nve-card nve-layout="span:6">Half width</nve-card>
<nve-card nve-layout="span:6">Half width</nve-card>
</section>
Column Spanning
The 12-column system offers these common patterns:
- Full width:
span:12 (1 item per row) - Half width:
span:6 (2 items per row) - Thirds:
span:4 (3 items per row) - Quarters:
span:3 (4 items per row) - Sixths:
span:2 (6 items per row) - Twelfths:
span:1 (12 items per row)
Grid Alignment
Like flexbox layouts, grid supports comprehensive alignment options that control how items position themselves within the grid container:
align:left align:right align:top align:bottom align:center align:horizontal-center align:vertical-center align:stretch align:horizontal-stretch align:vertical-stretch
Grid alignment works on the entire grid container. For individual item alignment, consider wrapping items in flexbox containers or using CSS custom properties for fine-tuned control. See the
child-controlled spans section for more granular layout control options.
Grid Layout Examples
Span Items 2
<section nve-layout="grid gap:md span-items:2">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md span-items:2">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card>
</section>
Span Items 6
<section nve-layout="grid gap:md span-items:6"><nve-card></nve-card><nve-card></nve-card></section>
<section nve-layout="grid gap:md span-items:6"><nve-card></nve-card><nve-card></nve-card></section>
Child-controlled Spans vs Parent-controlled Spans
The Elements grid system offers two approaches for controlling column spans, each suited to different design needs:
When to Use Parent-controlled Spans (span-items)
Use span-items on the grid container when:
- Uniform layouts: All items should have the same width
- Gallery grids: Photo galleries, card grids, or product listings
- Predictable patterns: Dashboard widgets, metric cards, or feature boxes
- Simplified markup: You want cleaner HTML without span attributes on each child
- Dynamic content: When the system generates items dynamically and they should maintain consistent sizing
<!-- All children automatically span 4 columns (3 per row) -->
<section nve-layout="grid gap:md span-items:4">
<nve-card>Feature 1</nve-card>
<nve-card>Feature 2</nve-card>
<nve-card>Feature 3</nve-card>
<!-- Add more cards - they'll all be the same size -->
</section>
<!-- All children automatically span 4 columns (3 per row) -->
<section nve-layout="grid gap:md span-items:4">
<nve-card>Feature 1</nve-card>
<nve-card>Feature 2</nve-card>
<nve-card>Feature 3</nve-card>
<!-- Add more cards - they'll all be the same size -->
</section>
When to Use Child-controlled Spans (span)
Use individual span attributes on grid items when:
- Mixed layouts: Different items need different widths
- Editorial designs: Magazine-style layouts with varied content sizes
- Form layouts: Labels, inputs, and buttons of different widths
- Asymmetric designs: Sidebars, main content areas, and feature blocks
- Precise control: Each element needs specific column spanning
<!-- Each child controls its own width -->
<section nve-layout="grid gap:md">
<header nve-layout="span:12">Full-width header</header>
<nav nve-layout="span:3">Narrow sidebar</nav>
<main nve-layout="span:9">Wide content area</main>
<footer nve-layout="span:12">Full-width footer</footer>
</section>
<!-- Each child controls its own width -->
<section nve-layout="grid gap:md">
<header nve-layout="span:12">Full-width header</header>
<nav nve-layout="span:3">Narrow sidebar</nav>
<main nve-layout="span:9">Wide content area</main>
<footer nve-layout="span:12">Full-width footer</footer>
</section>
Combining Both Approaches
You can mix both approaches for the most flexibility. Items with explicit span values override the parent's span-items setting:
<!-- Most items span 4 columns, but some override -->
<section nve-layout="grid gap:md span-items:4">
<nve-card>Standard width</nve-card>
<nve-card>Standard width</nve-card>
<nve-card nve-layout="span:12">Full width featured item</nve-card>
<nve-card>Standard width</nve-card>
<nve-card>Standard width</nve-card>
</section>
<!-- Most items span 4 columns, but some override -->
<section nve-layout="grid gap:md span-items:4">
<nve-card>Standard width</nve-card>
<nve-card>Standard width</nve-card>
<nve-card nve-layout="span:12">Full width featured item</nve-card>
<nve-card>Standard width</nve-card>
<nve-card>Standard width</nve-card>
</section>
- Parent-controlled (
span-items): More efficient for large grids with uniform items - Child-controlled (
span): Better for complex layouts with specific requirements - Mixed approach: Use sparingly to maintain code clarity
Child-controlled Spans Example
<section nve-layout="grid gap:md">
<span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span
><span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span
><span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span
><span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:5"><nve-card></nve-card></span>
<span nve-layout="span:5"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:6"><nve-card></nve-card></span>
<span nve-layout="span:6"><nve-card></nve-card></span>
<span nve-layout="span:7"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:8"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:9"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
</section>
<section nve-layout="grid gap:md">
<span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span
><span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span
><span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span
><span><nve-card></nve-card></span><span><nve-card></nve-card></span><span><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:5"><nve-card></nve-card></span>
<span nve-layout="span:5"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:6"><nve-card></nve-card></span>
<span nve-layout="span:6"><nve-card></nve-card></span>
<span nve-layout="span:7"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
<span nve-layout="span:2"><nve-card></nve-card></span>
<span nve-layout="span:8"><nve-card></nve-card></span>
<span nve-layout="span:4"><nve-card></nve-card></span>
<span nve-layout="span:9"><nve-card></nve-card></span>
<span nve-layout="span:3"><nve-card></nve-card></span>
</section>
Align Top
<section nve-layout="grid gap:md align:top align:left">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:top align:left">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Vertical Center
<section nve-layout="grid gap:md align:vertical-center align:left">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:vertical-center align:left">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Bottom
<section nve-layout="grid gap:md align:bottom align:left">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:bottom align:left">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Horizontal Center
<section nve-layout="grid gap:md align:horizontal-center">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:horizontal-center">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Center
<section nve-layout="grid gap:md align:center">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:center">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Center and Bottom
<section nve-layout="grid gap:md align:horizontal-center align:bottom">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:horizontal-center align:bottom">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Top and Right
<section nve-layout="grid gap:md align:top align:right">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:top align:right">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Center and Right
<section nve-layout="grid gap:md align:vertical-center align:right">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:vertical-center align:right">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Bottom and Right
<section nve-layout="grid gap:md align:bottom align:right">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:bottom align:right">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Horizontal Stretch
<section nve-layout="grid gap:md align:horizontal-stretch">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:horizontal-stretch">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Vertical Stretch
<section nve-layout="grid gap:md align:vertical-stretch">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:vertical-stretch">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Align Full Stretch
<section nve-layout="grid gap:md align:stretch">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
<section nve-layout="grid gap:md align:stretch">
<nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card
><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card><nve-card></nve-card>
</section>
Common Grid Patterns
Dashboard Layout
<main nve-layout="grid gap:lg">
<!-- Header spans full width -->
<header nve-layout="span:12">
<h1>Dashboard</h1>
</header>
<!-- Metrics cards in quarters -->
<nve-card nve-layout="span:3">Metric 1</nve-card>
<nve-card nve-layout="span:3">Metric 2</nve-card>
<nve-card nve-layout="span:3">Metric 3</nve-card>
<nve-card nve-layout="span:3">Metric 4</nve-card>
<!-- Main content with sidebar -->
<section nve-layout="span:8">Main Content</section>
<aside nve-layout="span:4">Sidebar</aside>
</main>
<main nve-layout="grid gap:lg">
<!-- Header spans full width -->
<header nve-layout="span:12">
<h1>Dashboard</h1>
</header>
<!-- Metrics cards in quarters -->
<nve-card nve-layout="span:3">Metric 1</nve-card>
<nve-card nve-layout="span:3">Metric 2</nve-card>
<nve-card nve-layout="span:3">Metric 3</nve-card>
<nve-card nve-layout="span:3">Metric 4</nve-card>
<!-- Main content with sidebar -->
<section nve-layout="span:8">Main Content</section>
<aside nve-layout="span:4">Sidebar</aside>
</main>
<form nve-layout="grid gap:md">
<!-- Full width fields -->
<nve-input nve-layout="span:12" label="Email">
<input type="email" placeholder="Email" />
</nve-input>
<!-- Half width fields -->
<nve-input nve-layout="span:6" label="First Name">
<input type="text" placeholder="First Name" />
</nve-input>
<nve-input nve-layout="span:6" label="Last Name">
<input type="text" placeholder="Last Name" />
</nve-input>
<!-- Third width fields -->
<nve-input nve-layout="span:4" label="City">
<input type="text" placeholder="City" />
</nve-input>
<nve-select nve-layout="span:4" label="State">
<select>
<option value selected disabled hidden>Select State</option>
</select>
</nve-select>
<nve-input nve-layout="span:4" label="Zip">
<input type="text" placeholder="Zip" />
</nve-input>
</form>
<form nve-layout="grid gap:md">
<!-- Full width fields -->
<nve-input nve-layout="span:12" label="Email">
<input type="email" placeholder="Email" />
</nve-input>
<!-- Half width fields -->
<nve-input nve-layout="span:6" label="First Name">
<input type="text" placeholder="First Name" />
</nve-input>
<nve-input nve-layout="span:6" label="Last Name">
<input type="text" placeholder="Last Name" />
</nve-input>
<!-- Third width fields -->
<nve-input nve-layout="span:4" label="City">
<input type="text" placeholder="City" />
</nve-input>
<nve-select nve-layout="span:4" label="State">
<select>
<option value selected disabled hidden>Select State</option>
</select>
</nve-select>
<nve-input nve-layout="span:4" label="Zip">
<input type="text" placeholder="Zip" />
</nve-input>
</form>
Card Gallery
<section nve-layout="grid gap:lg span-items:4 align:stretch">
<nve-card>
<nve-card-header>Feature 1</nve-card-header>
<nve-card-content>Description</nve-card-content>
</nve-card>
<!-- More cards... -->
</section>
<section nve-layout="grid gap:lg span-items:4 align:stretch">
<nve-card>
<nve-card-header>Feature 1</nve-card-header>
<nve-card-content>Description</nve-card-content>
</nve-card>
<!-- More cards... -->
</section>
Best Practices
- Start with 12 columns: This provides flexibility for responsive design patterns
- Use semantic HTML: Apply grid to meaningful containers like
<main>, <section>, <nav> - Consistent gaps: Use standard gap spacing throughout your layout
- Plan for responsiveness: Consider how your grid adapts on smaller screens
- Combine with flexbox: Use grid for layout structure, flexbox for component details
Browser Support: all modern browsers support CSS Grid. For older browser support, ensure you have appropriate fallbacks or polyfills in place.
Next Steps