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-x adds horizontal gutters to the cells; grid-margin-x uses margins. Pick one per row — combining them doubles the spacing.
  • Foundation has no vertical rhythm class for sections. A single .section class in your own Sass with padding is much easier to keep consistent than per-section utilities.
  • text-center exists in the prototype classes. If you dropped that component to save bytes, you will need your own utility.
  • The hero uses align-middle on 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>
MistakeSymptomFix
Off-canvas outside the wrapperPanel slides from nowherePut the panel inside .off-canvas-wrapper
grid-margin and grid-padding togetherDoubled guttersUse one gutter model per row
stack on a wide tableRows become unreadable blocks on desktopWrap in table-scroll, or only stack at small sizes
Nesting grid-containerContent narrower than the headerOne container per horizontal band
Sweeping foundation() after every partial loadDuplicate plugin instancesInitialise only the inserted subtree
Custom left offsets with RTL enabledLayout breaks in ArabicUse 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

  1. Choose the gutter model once — margin or padding — and use it consistently across the site.
  2. Decide the shell before writing sections: page scroll or fixed regions with an inner scroller.
  3. Import components in the settings file as you add them, and remove the ones you stop using.
  4. Test at 320px, at the medium breakpoint and at 200% zoom before calling a page finished.
  5. Check one RTL locale and one reduced-motion session while the layout is still fresh.
  6. 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.

Building navigation Accessibility and RTL support

Last refreshed 2026-09-18.