Building a complete page with Foundation
Assemble a marketing page and a dashboard shell with the XY grid and Foundation's components, including the composition mistakes that cost the most time.
Marketing page
<div class="top-bar" id="siteNav">
<div class="top-bar-left">
<ul class="dropdown menu" data-dropdown-menu>
<li class="menu-text">Acme</li>
<li><a href="#features">Features</a></li>
<li><a href="#pricing">Pricing</a></li>
</ul>
</div>
<div class="top-bar-right">
<ul class="menu">
<li><a class="button small" href="/signup/">Start free</a></li>
</ul>
</div>
</div>
<section class="grid-container grid-container-padded">
<div class="grid-x grid-padding-x grid-padding-y align-middle">
<div class="cell large-6">
<p class="label primary">Now in beta</p>
<h1 class="h2">Ship a responsive interface this week</h1>
<p class="lead">A grid, a component library and a theme system in one dependency.</p>
<div class="button-group">
<a class="button large" href="/signup/">Start free</a>
<a class="button large hollow" href="/docs/">Read the docs</a>
</div>
</div>
<div class="cell large-6">
<img class="thumbnail" src="/img/product.webp" alt="Screenshot of the dashboard" width="1200" height="900">
</div>
</div>
</section>
<section id="features" class="grid-container grid-container-padded">
<h2 class="h4 text-center">Everything you need</h2>
<div class="grid-x grid-margin-x grid-margin-y">
<div class="cell medium-4">
<div class="card"><div class="card-section">
<span class="label secondary">Grid</span>
<h3 class="h6">Twelve columns, any breakpoint</h3>
<p>Layouts that hold from 320px upwards.</p>
</div></div>
</div>
</div>
</section>
<div class="callout large primary text-center">
<h2 class="h4">Ready to try it?</h2>
<a class="button large hollow" href="/signup/">Create an account</a>
</div>grid-padding-xadds horizontal gutters to the cells;grid-margin-xuses margins. Pick one per row — combining them doubles the spacing.- Foundation has no vertical rhythm class for sections. A single
.sectionclass in your own Sass with padding is much easier to keep consistent than per-section utilities. text-centerexists in the prototype classes. If you dropped that component to save bytes, you will need your own utility.- The hero uses
align-middleon the grid rather than exotic positioning — the XY grid supports vertical alignment natively, which was the whole point of the new grid.
Dashboard shell
<div class="off-canvas-wrapper">
<div class="off-canvas-wrapper-inner" data-off-canvas-wrapper>
<div class="off-canvas position-left" id="dashNav" data-off-canvas data-transition="overlap">
<ul class="vertical menu" data-accordion-menu>
<li class="menu-text">Acme</li>
<li><a href="/dashboard/" class="is-active">Overview</a></li>
<li><a href="/invoices/">Invoices</a></li>
<li><a href="/settings/">Settings</a></li>
</ul>
</div>
<div class="off-canvas-content" data-off-canvas-content>
<div class="top-bar">
<div class="top-bar-left">
<button class="button small show-for-medium-only" type="button" data-toggle="dashNav">Menu</button>
<ul class="menu"><li class="menu-text">Overview</li></ul>
</div>
<div class="top-bar-right">
<ul class="menu">
<li><input type="search" placeholder="Search" aria-label="Search invoices"></li>
</ul>
</div>
</div>
<main class="grid-container fluid">
<div class="grid-x grid-margin-x grid-margin-y">
<div class="cell small-6 large-3">
<div class="stat-card">
<p class="stat">$84,120</p>
<p class="subheader">Revenue this month</p>
</div>
</div>
<div class="cell small-6 large-3">
<div class="stat-card">
<p class="stat">1,284</p>
<p class="subheader">Active subscriptions</p>
</div>
</div>
</div>
<div class="card">
<div class="card-divider">Recent invoices</div>
<div class="table-scroll">
<table class="hover stack">
<thead><tr><th scope="col">Invoice</th><th scope="col" class="text-right">Total</th></tr></thead>
<tbody>
<tr><td>#1042</td><td class="text-right">140.00</td></tr>
<tr><td>#1043</td><td class="text-right">12.50</td></tr>
</tbody>
</table>
</div>
</div>
</main>
</div>
</div>
</div>| Mistake | Symptom | Fix |
|---|---|---|
| Off-canvas outside the wrapper | Panel slides from nowhere | Put the panel inside .off-canvas-wrapper |
grid-margin and grid-padding together | Doubled gutters | Use one gutter model per row |
stack on a wide table | Rows become unreadable blocks on desktop | Wrap in table-scroll, or only stack at small sizes |
Nesting grid-container | Content narrower than the header | One container per horizontal band |
Sweeping foundation() after every partial load | Duplicate plugin instances | Initialise only the inserted subtree |
Custom left offsets with RTL enabled | Layout breaks in Arabic | Use logical properties |
⚠️
The most common Foundation performance problem is calling
$(document).foundation() after each AJAX update. It walks the whole document every time and re-runs plugins on elements that already have instances. Initialise the inserted subtree instead: $newContent.foundation().Composition checklist
- Choose the gutter model once — margin or padding — and use it consistently across the site.
- Decide the shell before writing sections: page scroll or fixed regions with an inner scroller.
- Import components in the settings file as you add them, and remove the ones you stop using.
- Test at 320px, at the medium breakpoint and at 200% zoom before calling a page finished.
- Check one RTL locale and one reduced-motion session while the layout is still fresh.
- Run the page with the JavaScript disabled to confirm the content is still readable.
// A small, reusable hydration helper keeps plugin init predictable.
function hydrateFoundation(root = document) {
const $root = $(root);
// destroy anything that already exists inside the region to avoid duplicates
$root.find('[data-reveal]').each((_, el) => {
Foundation.Reveal.getInstance($(el))?.destroy();
});
$root.foundation();
}
// usage after replacing a fragment
const $region = $('#invoices');
$region.html(renderRows(rows));
hydrateFoundation($region);FAQ
How should the sidebar behave on small screens?
Put it in an off-canvas panel and add
show-for-medium-only to the trigger, then keep the sidebar itself out of the desktop flow below the medium breakpoint. Duplicating navigation into the panel is acceptable; a squeezed sidebar is not.Is Foundation 6 still maintained?
It receives occasional compatibility releases rather than active feature work. That is a legitimate reason to choose it or to avoid it — it is stable and well documented, but new components and a jQuery-free version should not be expected.
Related
Building navigation Accessibility and RTL support
Last refreshed 2026-09-18.