Blocks · Navigation
Site footer
Brand, link columns and a legal row; on the page or as an inverted band that closes it.
85% of the 2,062 sites in The UI Index have a footer (1,753 sites).
Both previews render the same markup; the HTML tab below is that markup without a framework.
Install
- React
- npx shadcn@
latest add https:// www.themes.dev/ caseroom/ r/ site-footer.json - Astro
- npx shadcn@
latest add https:// www.themes.dev/ caseroom/ r/ astro/ site-footer.json
Or copy the files below into your project. They need clsx, tailwind-merge and the components they import, and the Caseroom theme. The HTML needs only the compiled CSS.
/** The site footer (ported from the themes' sections/footer): brand and a line about the product, link columns,
* and a legal row. columns sits on the page's ground with space above; band is an inverted ground (class
* inverted from the theme), the page's closing bookend. Links are 32px targets. */
export const siteFooter = {
root: '@container bg-background px-6 pt-16 pb-10 text-foreground',
band: 'inverted',
inner: 'mx-auto flex max-w-6xl flex-col gap-12',
top: 'grid gap-12 @3xl:grid-cols-[1.2fr_2fr]',
brand: 'flex flex-col gap-3',
brandName: 'text-[15px] font-semibold tracking-[-0.02em]',
tagline: 'max-w-xs text-sm text-pretty text-muted-foreground',
// Three columns at every width: two would leave the third group alone on its row.
groups: 'grid grid-cols-3 gap-4 @md:gap-6 @lg:gap-8 [&>*]:min-w-0',
group: 'flex flex-col gap-2',
groupTitle: 'text-sm font-medium',
groupList: 'm-0 flex list-none flex-col p-0',
link: '-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70',
legal: 'flex flex-col gap-3 border-t pt-6 text-sm text-muted-foreground @xl:flex-row @xl:items-center @xl:justify-between',
legalList: 'm-0 flex list-none flex-wrap gap-x-5 p-0',
};
export type FooterGroup = { title: string; links: { label: string; href: string }[] };
export type FooterContent = {
brand: string;
tagline?: string;
groups: FooterGroup[];
legal: { label: string; href: string }[];
/** The small print, e.g. "© 2026 Northwind". */
note: string;
variant?: 'columns' | 'band';
};import { cn } from '@/lib/utils';
import { siteFooter as c, type FooterContent } from './site-footer.classes';
export type SiteFooterProps = FooterContent & { className?: string };
/** The site footer: brand, link columns and a legal row; band puts it on an inverted ground. */
export function SiteFooter({ brand, tagline, groups, legal, note, variant = 'columns', className }: SiteFooterProps) {
return (
<footer className={cn(c.root, variant === 'band' && c.band, className)}>
<div className={c.inner}>
<div className={c.top}>
<div className={c.brand}>
<p className={c.brandName}>{brand}</p>
{tagline && <p className={c.tagline}>{tagline}</p>}
</div>
<div className={c.groups}>
{groups.map((g) => (
<nav key={g.title} aria-label={g.title} className={c.group}>
<p className={c.groupTitle}>{g.title}</p>
<ul className={c.groupList}>
{g.links.map((l) => (
<li key={l.href + l.label}><a href={l.href} className={c.link}>{l.label}</a></li>
))}
</ul>
</nav>
))}
</div>
</div>
<div className={c.legal}>
<p>{note}</p>
<ul className={c.legalList} aria-label="Legal">
{legal.map((l) => <li key={l.href + l.label}><a href={l.href} className={c.link}>{l.label}</a></li>)}
</ul>
</div>
</div>
</footer>
);
}---
import { cn } from '@/lib/utils';
import { siteFooter as c, type FooterContent } from './site-footer.classes';
type Props = FooterContent & { class?: string };
const { brand, tagline, groups, legal, note, variant = 'columns', class: className } = Astro.props;
---
<footer class={cn(c.root, variant === 'band' && c.band, className)}>
<div class={c.inner}>
<div class={c.top}>
<div class={c.brand}>
<p class={c.brandName}>{brand}</p>
{tagline && <p class={c.tagline}>{tagline}</p>}
</div>
<div class={c.groups}>
{
groups.map((g) => (
<nav aria-label={g.title} class={c.group}>
<p class={c.groupTitle}>{g.title}</p>
<ul class={c.groupList}>
{g.links.map((l) => (
<li><a href={l.href} class={c.link}>{l.label}</a></li>
))}
</ul>
</nav>
))
}
</div>
</div>
<div class={c.legal}>
<p>{note}</p>
<ul class={c.legalList} aria-label="Legal">
{legal.map((l) => <li><a href={l.href} class={c.link}>{l.label}</a></li>)}
</ul>
</div>
</div>
</footer>/** The site footer (ported from the themes' sections/footer): brand and a line about the product, link columns,
* and a legal row. columns sits on the page's ground with space above; band is an inverted ground (class
* inverted from the theme), the page's closing bookend. Links are 32px targets. */
export const siteFooter = {
root: '@container bg-background px-6 pt-16 pb-10 text-foreground',
band: 'inverted',
inner: 'mx-auto flex max-w-6xl flex-col gap-12',
top: 'grid gap-12 @3xl:grid-cols-[1.2fr_2fr]',
brand: 'flex flex-col gap-3',
brandName: 'text-[15px] font-semibold tracking-[-0.02em]',
tagline: 'max-w-xs text-sm text-pretty text-muted-foreground',
// Three columns at every width: two would leave the third group alone on its row.
groups: 'grid grid-cols-3 gap-4 @md:gap-6 @lg:gap-8 [&>*]:min-w-0',
group: 'flex flex-col gap-2',
groupTitle: 'text-sm font-medium',
groupList: 'm-0 flex list-none flex-col p-0',
link: '-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70',
legal: 'flex flex-col gap-3 border-t pt-6 text-sm text-muted-foreground @xl:flex-row @xl:items-center @xl:justify-between',
legalList: 'm-0 flex list-none flex-wrap gap-x-5 p-0',
};
export type FooterGroup = { title: string; links: { label: string; href: string }[] };
export type FooterContent = {
brand: string;
tagline?: string;
groups: FooterGroup[];
legal: { label: string; href: string }[];
/** The small print, e.g. "© 2026 Northwind". */
note: string;
variant?: 'columns' | 'band';
};<footer class="@container bg-background px-6 pt-16 pb-10 text-foreground">
<div class="mx-auto flex max-w-6xl flex-col gap-12">
<div class="grid gap-12 @3xl:grid-cols-[1.2fr_2fr]">
<div class="flex flex-col gap-3">
<p class="text-[15px] font-semibold tracking-[-0.02em]">Northwind</p>
<p class="max-w-xs text-sm text-pretty text-muted-foreground">Deploys for small teams that ship every day.</p>
</div>
<div class="grid grid-cols-3 gap-4 @md:gap-6 @lg:gap-8 [&>*]:min-w-0">
<nav aria-label="Product" class="flex flex-col gap-2">
<p class="text-sm font-medium">Product</p>
<ul class="m-0 flex list-none flex-col p-0">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Features
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Pricing
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Changelog
</a>
</li>
</ul>
</nav>
<nav aria-label="Company" class="flex flex-col gap-2">
<p class="text-sm font-medium">Company</p>
<ul class="m-0 flex list-none flex-col p-0">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
About
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Careers
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Contact
</a>
</li>
</ul>
</nav>
<nav aria-label="Resources" class="flex flex-col gap-2">
<p class="text-sm font-medium">Resources</p>
<ul class="m-0 flex list-none flex-col p-0">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Docs
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Status
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Security
</a>
</li>
</ul>
</nav>
</div>
</div>
<div class="flex flex-col gap-3 border-t pt-6 text-sm text-muted-foreground @xl:flex-row @xl:items-center @xl:justify-between">
<p>© 2026 Northwind. Made in Utrecht.</p>
<ul class="m-0 flex list-none flex-wrap gap-x-5 p-0" aria-label="Legal">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Privacy
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Terms
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Cookies
</a>
</li>
</ul>
</div>
</div>
</footer>
<footer class="@container bg-background px-6 pt-16 pb-10 text-foreground inverted">
<div class="mx-auto flex max-w-6xl flex-col gap-12">
<div class="grid gap-12 @3xl:grid-cols-[1.2fr_2fr]">
<div class="flex flex-col gap-3">
<p class="text-[15px] font-semibold tracking-[-0.02em]">Northwind</p>
<p class="max-w-xs text-sm text-pretty text-muted-foreground">Deploys for small teams that ship every day.</p>
</div>
<div class="grid grid-cols-3 gap-4 @md:gap-6 @lg:gap-8 [&>*]:min-w-0">
<nav aria-label="Product" class="flex flex-col gap-2">
<p class="text-sm font-medium">Product</p>
<ul class="m-0 flex list-none flex-col p-0">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Features
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Pricing
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Changelog
</a>
</li>
</ul>
</nav>
<nav aria-label="Company" class="flex flex-col gap-2">
<p class="text-sm font-medium">Company</p>
<ul class="m-0 flex list-none flex-col p-0">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
About
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Careers
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Contact
</a>
</li>
</ul>
</nav>
<nav aria-label="Resources" class="flex flex-col gap-2">
<p class="text-sm font-medium">Resources</p>
<ul class="m-0 flex list-none flex-col p-0">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Docs
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Status
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Security
</a>
</li>
</ul>
</nav>
</div>
</div>
<div class="flex flex-col gap-3 border-t pt-6 text-sm text-muted-foreground @xl:flex-row @xl:items-center @xl:justify-between">
<p>© 2026 Northwind. Made in Utrecht.</p>
<ul class="m-0 flex list-none flex-wrap gap-x-5 p-0" aria-label="Legal">
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Privacy
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Terms
</a>
</li>
<li>
<a href="#" class="-mx-1 inline-flex min-h-8 items-center rounded-sm px-1 text-sm text-muted-foreground transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70">
Cookies
</a>
</li>
</ul>
</div>
</div>
</footer>