footer — a designed ending, not storage
Stage: Phase 6 — Build - Reads: design/SYSTEM.md, design/SITEMAP.md, design/BRIEF.md - Writes: components/layout/footer.tsx
Standard
The footer is the last thing a convinced visitor sees — the site's sign-off, with a point of view. First-grade means:
- A deliberate closing gesture: scale, a surface shift, or a final CTA. The page visibly ENDS; it never just trails off.
- Every link resolves — zero
href="#". Groups are labeled. The legal row is complete per BRIEF.md.
- The surface is a decision: footers often flip to the dark surface (or the inverse) — re-decided per taste's dark-mode rule, contrast verified on the flipped surface, both themes.
- A newsletter row (when BRIEF.md wants one) is a real designed form wired to a server action — never a decorative input.
Process
- Read BRIEF.md (legal requirements, social channels, newsletter yes/no) and SITEMAP.md — decide which pages earn footer links; not all do.
- Pick a variant below by site energy; decide the surface (flip or continue) against SYSTEM tokens.
- Order by attention, top to bottom: closing gesture → primary link groups → newsletter → social → legal strip.
- State pass: link hover matches the nav vocabulary; newsletter input focus/error/success designed; social icons from lucide at one size and stroke width.
- Verify: keyboard-tab the entire footer, compute contrast on the flipped surface, click every link.
Variants
oversized-type closer — the brand name or a sign-off word at clamp(4rem, 18vw, 16rem), tight tracking, often baseline-cropped by the viewport bottom edge as a deliberate cut; a slim link/legal row above it. When: portfolio, agency, fashion, any type-led direction — the strongest closing gesture available, and free asymmetry. Mark the giant word aria-hidden="true" when the brand name already appears in the legal row.
columnar sitemap — 3-4 labeled link columns plus a brand column. When: 8+ pages, SaaS with docs, e-commerce. Discipline: max 4 columns, 4-6 links each, group labels in the muted tone — a footer is not sitemap.xml.
minimal strip — one or two rows: wordmark, short nav, legal, social. When: one-pagers, portfolios, local business. A small site wearing a columnar footer looks like it is cosplaying a bigger one.
CTA finale — a full-width conversion moment ("Ready? Start your project.") with the primary CTA, then a compact link/legal strip below. When: SaaS/agency where the footer is the last conversion chance. The CTA repeats the hero's offer in the same primary style — one primary, still.
Baseline-cropped closer, the standard construction:
<div className="overflow-hidden">
<p aria-hidden="true" className="text-[clamp(4rem,18vw,16rem)] leading-[0.8] tracking-tighter translate-y-[12%]">
STUDIO
</p>
</div>
Rules
- The seam is designed: the hand-off from the last section into the footer gets release space (96-160px) or a hard surface cut — never a default
py-24 drift.
- Scale discipline: the closing gesture takes 50-70% of footer height. Column links at 0.875-0.9375rem with relaxed leading; group labels 0.75-0.8125rem, uppercase or small-caps, muted tone.
- Responsive: 4 columns → 2 at 768px → single stack at 375px, groups and labels intact. The oversized word scales through its clamp() and never wraps — shorten the word, not the size.
- Touch: every footer link is a 44px hit target on mobile — pad the hit area, not the visual.
- Back-to-top affordance only on pages taller than ~4 viewports, built into the legal strip — never a floating circle button.
- Footer link hover uses the exact same move as the header nav (
ultraweb:micro-interactions vocabulary); two vocabularies on one page reads as two sites.
Content organization
- Legal strip: bottom row, smallest type that still passes AA.
© {new Date().getFullYear()} Brand computed — never a hardcoded year. Privacy/terms/imprint links exactly as BRIEF.md requires.
- Social: lucide icons at one size (20px) and one stroke width, 44px hit targets,
aria-label per icon, only channels the brand actually uses.
- Newsletter: visible label (never placeholder-as-label), single email field + button, zod-validated server action, inline success and error states — full pattern in
ultraweb:forms.
- Landmarks:
<footer> element; a nav inside it gets aria-label="Footer" so it does not collide with the header nav.
Accessibility
- The footer introduces no stray page headings: group labels are either plain text or a consistent heading level under one (optionally visually-hidden) footer
<h2> — never skipped levels.
- Contrast on the flipped surface computed for text, icons, AND the newsletter input's border and placeholder — muted tones that pass on light routinely fail on dark.
- Focus order follows visual order; the oversized
aria-hidden word is never focusable and never announced.
- Newsletter errors are announced (
aria-describedby on the input, live region for the result), not just painted red.
Anti-patterns
href="#" social or legal placeholders — real URL or the link doesn't ship.
- Hardcoded copyright year — greppable
© 20 followed by a literal year.
- "Made with ❤️" and emoji sign-offs — banned list.
- Link dump: every route ever built, unlabeled, five columns deep.
- Newsletter input with no wired action, no label, or no success state — decorative forms are lies.
- A footer with the same surface, spacing, and rhythm as every other section — the page just stops.
- 10px legal text failing contrast on the flipped surface.
Worked example — Ledger & Lane, boutique law-firm footer
Moved to references/example.md — read only when this build's case is genuinely ambiguous; the sections above are the decision material.
Composes with
Moved to references/composes.md — the handoff map; load it when orchestrating this skill against its neighbors.
1---2name: footer3description: Design and build the site footer as a designed closing statement, never a link dump — four named variants (oversized-type closer, columnar sitemap, minimal strip, CTA finale), sitemap/legal/social organization, and a newsletter row wired to a real server action. Invoke during the Build phase for any footer work — trigger phrases — "footer", "bottom of the page", "site footer", "newsletter signup", "legal links", "social links row", "closing section".4---56# footer — a designed ending, not storage78**Stage:** Phase 6 — Build - **Reads:** design/SYSTEM.md, design/SITEMAP.md, design/BRIEF.md - **Writes:** components/layout/footer.tsx910## Standard1112The footer is the last thing a convinced visitor sees — the site's sign-off, with a point of view. First-grade means:1314- A deliberate closing gesture: scale, a surface shift, or a final CTA. The page visibly ENDS; it never just trails off.15- Every link resolves — zero `href="#"`. Groups are labeled. The legal row is complete per BRIEF.md.16- The surface is a decision: footers often flip to the dark surface (or the inverse) — re-decided per taste's dark-mode rule, contrast verified on the flipped surface, both themes.17- A newsletter row (when BRIEF.md wants one) is a real designed form wired to a server action — never a decorative input.1819## Process20211. Read BRIEF.md (legal requirements, social channels, newsletter yes/no) and SITEMAP.md — decide which pages earn footer links; not all do.222. Pick a variant below by site energy; decide the surface (flip or continue) against SYSTEM tokens.233. Order by attention, top to bottom: closing gesture → primary link groups → newsletter → social → legal strip.244. State pass: link hover matches the nav vocabulary; newsletter input focus/error/success designed; social icons from lucide at one size and stroke width.255. Verify: keyboard-tab the entire footer, compute contrast on the flipped surface, click every link.2627## Variants2829**oversized-type closer** — the brand name or a sign-off word at `clamp(4rem, 18vw, 16rem)`, tight tracking, often baseline-cropped by the viewport bottom edge as a deliberate cut; a slim link/legal row above it. When: portfolio, agency, fashion, any type-led direction — the strongest closing gesture available, and free asymmetry. Mark the giant word `aria-hidden="true"` when the brand name already appears in the legal row.3031**columnar sitemap** — 3-4 labeled link columns plus a brand column. When: 8+ pages, SaaS with docs, e-commerce. Discipline: max 4 columns, 4-6 links each, group labels in the muted tone — a footer is not sitemap.xml.3233**minimal strip** — one or two rows: wordmark, short nav, legal, social. When: one-pagers, portfolios, local business. A small site wearing a columnar footer looks like it is cosplaying a bigger one.3435**CTA finale** — a full-width conversion moment ("Ready? Start your project.") with the primary CTA, then a compact link/legal strip below. When: SaaS/agency where the footer is the last conversion chance. The CTA repeats the hero's offer in the same primary style — one primary, still.3637Baseline-cropped closer, the standard construction:3839```tsx40<div className="overflow-hidden">41 <p aria-hidden="true" className="text-[clamp(4rem,18vw,16rem)] leading-[0.8] tracking-tighter translate-y-[12%]">42 STUDIO43 </p>44</div>45```4647## Rules4849- The seam is designed: the hand-off from the last section into the footer gets release space (96-160px) or a hard surface cut — never a default `py-24` drift.50- Scale discipline: the closing gesture takes 50-70% of footer height. Column links at 0.875-0.9375rem with relaxed leading; group labels 0.75-0.8125rem, uppercase or small-caps, muted tone.51- Responsive: 4 columns → 2 at 768px → single stack at 375px, groups and labels intact. The oversized word scales through its clamp() and never wraps — shorten the word, not the size.52- Touch: every footer link is a 44px hit target on mobile — pad the hit area, not the visual.53- Back-to-top affordance only on pages taller than ~4 viewports, built into the legal strip — never a floating circle button.54- Footer link hover uses the exact same move as the header nav (`ultraweb:micro-interactions` vocabulary); two vocabularies on one page reads as two sites.5556## Content organization5758- Legal strip: bottom row, smallest type that still passes AA. `© {new Date().getFullYear()} Brand` computed — never a hardcoded year. Privacy/terms/imprint links exactly as BRIEF.md requires.59- Social: lucide icons at one size (20px) and one stroke width, 44px hit targets, `aria-label` per icon, only channels the brand actually uses.60- Newsletter: visible label (never placeholder-as-label), single email field + button, zod-validated server action, inline success and error states — full pattern in `ultraweb:forms`.61- Landmarks: `<footer>` element; a nav inside it gets `aria-label="Footer"` so it does not collide with the header nav.6263## Accessibility6465- The footer introduces no stray page headings: group labels are either plain text or a consistent heading level under one (optionally visually-hidden) footer `<h2>` — never skipped levels.66- Contrast on the flipped surface computed for text, icons, AND the newsletter input's border and placeholder — muted tones that pass on light routinely fail on dark.67- Focus order follows visual order; the oversized `aria-hidden` word is never focusable and never announced.68- Newsletter errors are announced (`aria-describedby` on the input, live region for the result), not just painted red.6970## Anti-patterns7172- `href="#"` social or legal placeholders — real URL or the link doesn't ship.73- Hardcoded copyright year — greppable `© 20` followed by a literal year.74- "Made with ❤️" and emoji sign-offs — banned list.75- Link dump: every route ever built, unlabeled, five columns deep.76- Newsletter input with no wired action, no label, or no success state — decorative forms are lies.77- A footer with the same surface, spacing, and rhythm as every other section — the page just stops.78- 10px legal text failing contrast on the flipped surface.7980## Worked example — Ledger & Lane, boutique law-firm footer8182Moved to `references/example.md` — read only when this build's case is genuinely ambiguous; the sections above are the decision material.8384## Composes with8586Moved to `references/composes.md` — the handoff map; load it when orchestrating this skill against its neighbors.