Sections
Site footer
Multi-column footer with link columns and contact details.
Installation
npx shadcn@latest add http://localhost:3000/r/site-footer.jsonMKT UI is not published yet, so this points at your local development server. Set NEXT_PUBLIC_REGISTRY_URL to the deployed origin to show the public command.
Also installs: container, phone-link.
Usage
import { SiteFooter } from "@/components/site-footer";
<SiteFooter
logo="Northgate Plumbing"
description="Licensed plumbers across North Austin."
address={<><span className="block">2140 Burnet Road</span><span className="block">Austin, TX 78756</span></>}
phone={{ number: "(512) 555-0142" }}
email="hello@example.com"
columns={[
{
title: "Services",
links: [
{ label: "Emergency repairs", href: "/services/emergency" },
{ label: "Water heaters", href: "/services/water-heaters" },
],
},
{
title: "Hours",
links: [
{ label: "Mon–Fri 7am–6pm" },
{ label: "Saturday 8am–2pm" },
],
},
]}
copyright="© 2026 Northgate Plumbing."
legalLinks={[{ label: "Privacy", href: "/privacy" }]}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| logo (required) | ReactNode | — | Business name or logo element. |
| description | ReactNode | — | A sentence on what the business does. |
| columns | FooterColumn[] | [] | Link columns. Three or four is the readable maximum. |
| address | ReactNode | — | Postal address, rendered in an `<address>` element. |
| phone | { number, dial?, label? } | — | Tap-to-call number. |
| string | — | Rendered as a `mailto:` link. | |
| copyright | ReactNode | — | Legal line. The year is not added automatically — pass what you want shown. |
| legalLinks | FooterLink[] | [] | Privacy, terms, and similar, on the bottom row. |
| children | ReactNode | — | Extra content under the description, e.g. social icons. |
Behavior
Each column is a labeled <nav> landmark, named from its heading. A screen-reader
user landing in the footer hears "Services navigation" rather than four unlabelled
lists of links.
Entries without an href render as plain text. Opening hours are information, not
destinations; marking them up as links to nowhere is a small lie that a keyboard user
pays for in extra tab stops.
links: [
{ label: "Mon–Fri 7am–6pm" }, // text
{ label: "Book online", href: "/book" }, // link
]external: true adds target="_blank", rel="noreferrer noopener", and a
screen-reader-only "(opens in a new tab)" hint.
Limitations
- One layout. Minimal, contact-focused, and newsletter variants are not implemented yet.
- No social icon component yet — pass your own via
children. - Columns collapse to two at
smand one below that; the split is not configurable.