⚠️ Design system CSS not found. Check the path in cms/docs.config.js → designSystemPath, then re-run npm run docgen.

Footer

Identity, links and legal at the bottom of a page

Website / Footer
Download .md file
Open .md in new tab
On this page
  • Anatomy
  • Basic usage
  • The top region
  • Responsive
  • Accessibility
  • Usage rules
  • CSS reference
  • Use in another product

The footer is the block at the bottom of a page. It has two regions: an optional top carrying identity and link columns, and a bottom carrying the copyright and the legal links. On most sites the bottom region is the whole component — a single centred line — and the top only appears once a site has enough to say to need it.

It is the counterpart to the Site Header and shares its construction: a full-bleed outer element owning background and border, an inner element owning width and padding. Placement is the consumer's job. The footer knows nothing about the page above it.


Anatomy

footer.footer                      the component; full-bleed
  .footer-inner                    max-width, centring, inset
    .footer-top                    optional — three slots
      .footer-top-start              track 1, content flush left
      a.footer-logo                  track 2, centred
        .svg-logo.footer-logo-image
      .footer-top-end                track 3, content flush right
    .footer-bottom                 required
                                   optional attr: data-layout="center"
      p                              the copyright
      nav.footer-legal               optional legal links

Two things about this shape are deliberate.

The top region is three fixed slots, not a variable column count. The logo is the middle one and both sides are optional, so the arrangement has to hold with one side, the other, or neither. Every slot is placed by explicit grid line rather than left to auto-placement — a footer carrying only an end slot would otherwise be auto-placed into the first track and render on the left, and an absent slot has to keep holding its track open or the logo stops being centred the moment one side is dropped.

Links are , not . A Nav link carries the padding a header bar needs to turn each link into a full-height hit area. A footer column has no bar to fill, so the padding would only push the links apart. Owning the link also means the footer wraps its rows freely, without asking Nav to soften its rule that a header nav needing to wrap is a nav needing a drawer.


Basic usage

The bottom region alone, centred. This is what a tool page or a small site ships.

© 2026 By Default

<footer class="footer">
  <div class="footer-inner">
    <div class="footer-bottom" data-layout="center">
      <p class="text-size-small text-secondary">© 2026 By Default</p>
    </div>
  </div>
</footer>

With legal links

Drop data-layout="center" and the copyright falls to the start while the legal row is pushed to the end by an auto margin. "Cookie preferences" is a <button> because it opens a dialog rather than going anywhere — it still takes , so the row reads as one set.

© 2026 By Default

Terms of use Privacy notice Cookie Policy Accessibility
<div class="footer-bottom">
  <p class="text-size-small text-secondary">© 2026 By Default</p>
  <nav class="footer-legal" aria-label="Legal">
    <a class="footer-link" href="/terms">Terms of use</a>
    <a class="footer-link" href="/privacy">Privacy notice</a>
    <button type="button" class="footer-link">Cookie preferences</button>
  </nav>
</div>

The top region

The full shape: links flush left, logo centred, links flush right. Column headings take alongside the utility — the shape comes from the utility, and the footer only steps the colour down so the links stay the loudest thing in the slot.

Studio

About Work Contact

Resources

Design system Brand book Tools

© 2026 By Default

Terms of use Privacy notice
<div class="footer-top">
  <div class="footer-top-start">
    <h2 class="footer-label label" id="ft-studio">Studio</h2>
    <nav class="footer-links" aria-labelledby="ft-studio">
      <a class="footer-link" href="/about">About</a>
      <a class="footer-link" href="/work">Work</a>
    </nav>
  </div>
  <a class="footer-logo" href="/" aria-label="By Default, home">
    <div class="svg-logo footer-logo-image">
      <svg data-logo="by-default-primary-centered" width="100%" height="100%" viewBox="0 0 1050 505" fill="none" aria-hidden="true">…</svg>
    </div>
  </a>
  <div class="footer-top-end">
    <h2 class="footer-label label" id="ft-resources">Resources</h2>
    <nav class="footer-links" aria-labelledby="ft-resources">
      <a class="footer-link" href="/design-system">Design system</a>
      <a class="footer-link" href="/tools">Tools</a>
    </nav>
  </div>
</div>

Slots are optional

The logo alone still centres, because the side tracks keep their floor whether or not anything is in them. Emit only the slots you have — there is no empty <div> to write.

© 2026 By Default

<div class="footer-top">
  <a class="footer-logo" href="/" aria-label="By Default, home">
    <div class="svg-logo footer-logo-image">…</div>
  </a>
</div>

Responsive

At 768px the three tracks collapse to one and everything centres — including the end slot, which right-aligns only when there are three columns to align against. The pinned grid lines are released at the same time; a slot left pinned to line 3 would conjure implicit columns beside the single explicit one.

The legal row wraps rather than overflowing. It has no bar height to protect, so a second line is the correct answer where a header would need a drawer.


Accessibility

Requirement How
Landmark <footer> is the element. It maps to contentinfo only at the top level — as a sibling of <main>, never inside it
Named navigation Each <nav> needs a distinct accessible name once a page has more than one. aria-label="Legal" on the legal row; aria-labelledby on a column, pointing at its own heading
Column headings Ship a real heading (<h2>), so a screen-reader user can jump between slots. styles it without changing what it is
Touch targets carries min-block-size: 24px, meeting WCAG 2.2 AA 2.5.8
Current page Driven from aria-current="page", so the accessible state and the visible state cannot drift apart
Focus Inherited from the global focus rule

The demos above use <p>, not <h2> — do the opposite in production. A real heading inside a demo joins this page's outline and its table of contents, so the demo would advertise "Studio" and "Resources" as sections of the footer documentation. aria-labelledby works against any element, so the naming pattern shown is exactly the one to ship; only the element changes. The code samples show the <h2> you should actually write.

Name a nav "Legal", not "Footer navigation". Screen readers append the role themselves, so the latter announces as "Footer navigation navigation".

A control that opens a dialog is a <button>. "Cookie preferences" takes so it matches its neighbours, but it stays a button and announces as one. This bends Nav's rule about keeping non-navigation controls out of a <nav>, and does so knowingly: splitting one visual row across a landmark boundary to satisfy the rule would make the row worse for everyone.


Usage rules

Do:

  • Put as a sibling of <main>, so it is a real contentinfo landmark
  • Emit only the slots you have — absent slots keep their tracks open on their own
  • Use with for column headings, on a real heading element
  • Re-point --footer-background to re-skin, and the foreground tokens with it — --footer-text, --footer-label-color, --footer-logo-color and the three --footer-link-color-*

Don't:

  • Don't set margin-top: auto on the footer to push it down a short page. That is the page shell's job, and baking it in makes the component depend on a layout it cannot see
  • Don't use inside the footer. It carries a header bar's padding, and the two are meant to be able to diverge
  • Don't emit an empty slot to hold the shape
  • Don't re-point --footer-background alone. Every foreground has its own token precisely so a dark footer does not leave the logo or the headings stranded at their light-theme colours
  • Don't put page-layout properties like grid-area on from the component side

CSS reference

This section documents how the component is built. For usage, see the sections above.

Tokens

Token Default What it controls
none Content width. Full-bleed by default; set a length to align with a content column
Inset on the inner element; matches
Vertical size — the footer's answer to
Grid gap, the space either side of the hairline, and the bottom row's gap
Rhythm inside a slot: heading to links, link to link
160px Floor on each side track, so a short slot cannot drag the centre off
80px Logo height; width follows
Footer background
Footer foreground
var(--border-s) solid var(--border-faded) Top border and the hairline under the top region
Column heading colour
Logo colour
Link colour at rest
Link colour on hover
Link colour for aria-current="page"
24px Link target height; the WCAG 2.2 AA 2.5.8 floor
Space between links in the legal row

Selectors

Selector Purpose
Base component; background, top border, vertical padding
Width, centring, inset
The three-track grid
/ Slots on lines 1 and 3; the end slot right-aligns
Identity link, pinned to line 2 and centred
.svg-logo.footer-logo-image Logo sizing inside that link
Column heading colour; composes with
A stacked link set
One link, in a column or in the legal row
Copyright row; wraps
.footer-bottom[data-layout="center"] Centred variant for a lone copyright
Legal row; carries the auto margin and wraps

Key rules

Slot placement: margin-inline-start: auto on , never space-between — with a single child, space-between resolves to flex-start and a lone copyright would sit left when it should be pushed by nothing at all.

The end slot needs both align-items: flex-end and text-align: right. text-align alone cannot move a stretched flex child, only the text inside one, so without the first the links stay full-width and the alignment does nothing visible.

has no padding by design and takes its height from --footer-link-min-size. --font-s at --line-height-m is 19.2px, under the 24×24 target WCAG 2.2 AA asks for; min-block-size buys the height without an inset that would show the moment a background were added. It guarantees the block axis only — inline size comes from the label, so a link shorter than 24px wide relies on the spacing exception, which --footer-legal-gap at 12px satisfies.

Zero padding also means the global focus ring cannot draw inside the link. is therefore listed with the other zero-padding controls that flip outline-offset positive; without it the ring strikes through the first and last character.

Logical properties throughout (margin-inline, padding-block, min-block-size), so RTL works without a mirrored stylesheet.

Related

is the foundation utility the column headings borrow their shape from. Nav is the link set for a header or a drawer; the footer deliberately does not use it. Site Header is the same construction at the other end of the page.


Use in another product

The design system installs once per product:

npm install github:bydefaultstudio/design-system-dist#semver:^4.7.0

This component's styles ship in design-system.css. No JavaScript, nothing else to include.

On this page
  • Anatomy
  • Basic usage
  • The top region
  • Responsive
  • Accessibility
  • Usage rules
  • CSS reference
  • Use in another product
Previous Site Header
Next Bar

Was this page helpful?

We use this feedback to improve our documentation.

Thanks for your feedback

Send feedback

© 2026 By Default