UI.MD

Site Footer

The shared site chrome footer: a shell plus parts, from a one-line strip to a multi-column footer.

Installation

$
npx shadcn@latest add https://ui.mattdowney.com/r/site-footer.json

Usage

import {
  SiteFooter, SiteFooterAttribution, SiteFooterBrand, SiteFooterColumn,
  SiteFooterColumns, SiteFooterRow,
  siteFooterNavItemClass, siteFooterIconLinkClass,
} from "@/components/ui/site-footer"

Examples

Default strip

Pass no children and the shell renders the original single-row strip: attribution and copyright on one side, links on the other.

Page title

Page content ends here and the footer closes the column.

Multi-column

Brand on one side, the column region on the other, then a bottom bar. SiteFooterColumns puts the columns on equal grid tracks: packed into a flex row they size to their own content, so nothing lines up, and justify-between flings them to the edges. Two columns below sm, one track per column above it.

Page title

Page content ends here and the footer closes the column.

Centred

align="center" stacks the whole footer down the middle: the archetype for a small site or a single project page, where a start-aligned footer with one short link row looks abandoned in the corner. It reaches the parts through a scoped CSS rule rather than React context, so the footer stays a Server Component.

Page title

Page content ends here and the footer closes the column.

API Reference

PropTypeDefaultDescription
childrenSiteFooterReactNode-Rows, brand blocks, and columns. Wins over the strip props.
nameSiteFooter, SiteFooterAttributionstring"UI"The site's wordmark name for the default attribution, e.g. "SKILLS". The "using UI.MD" clause is dropped when the site is UI.MD itself.
attributionSiteFooterReactNode-Replaces the default credit line in the strip. Only for a site that genuinely needs different credits.
navSiteFooterReactNode-Strip links, styled with siteFooterNavItemClass.
justifySiteFooterRow"between" | "start" | "end""between"How the run distributes its children. between is what a footer row nearly always wants; the other two keep it packed to one side. Ignored under align="center", which centres every row.
dividerSiteFooterRowbooleanfalseA hairline above the row, for the legal bar under a tall footer. The line lands in the shell's own gap-8 and the row's padding matches it, so the rule sits evenly between the two zones instead of hugging one.
alignSiteFooter"start" | "center""start"center stacks the whole footer down the middle, reaching the parts through a scoped CSS rule rather than React context so the footer stays a Server Component.
titleSiteFooterColumnReactNode-Column heading above the links, rendered as the kit's group label: uppercase, tracking-wide, semibold, in text-foreground over muted links. Omit for an untitled stack.
childrenSiteFooterColumnsReactNode-Two or more <SiteFooterColumn />. They land on equal grid tracks, two-up below sm and one track each above it, however many you pass. Packed into a flex row instead they would size to their own content and fail to line up.
classNameSiteFooter, SiteFooterRow, SiteFooterBrand, SiteFooterColumn, SiteFooterColumnsstring-On <SiteFooter /> it merges onto the <footer>, not the inner chrome container. Pass mt-auto there when the page is a flex min-h-dvh flex-col column.