Skip to content

Mega footer

Six columns plus a status, version and locale strip.

Footersstarterfootermegaenterprisestatus

Live preview

full widthLive preview — open it in a new tab for the full-height version.
Open the preview in a new tab

Source

This exact file renders the preview above.

import Link from 'next/link'
import { Globe } from 'lucide-react'
import { BrandMark } from '@/components/library/brand'
import { Badge } from '@/components/ui/badge'
import { Container } from '@/components/ui/layout'
import { Status } from '@/components/ui/status'
import { productLinks, resourceLinks, companyLinks, megaMenu } from '@/content/nav-demo'

/**
 * Mega footer
 *
 * Six columns plus a status and locale strip. Appropriate for products with
 * genuinely large surface area — a mega footer over a five-page site is a
 * confession, not a feature.
 *
 * The system-status line is a real Status component so it carries an icon and
 * a word, not just a green dot.
 */
const columns = [
  { label: 'Build', links: megaMenu[0]?.links ?? [] },
  { label: 'Compose', links: megaMenu[1]?.links ?? [] },
  { label: 'Ship', links: megaMenu[2]?.links ?? [] },
  { label: 'Product', links: productLinks },
  { label: 'Resources', links: resourceLinks },
  { label: 'Company', links: companyLinks },
]

export default function MegaFooter() {
  return (
    <footer className="border-t border-line bg-surface-sunken">
      <Container size="wide" className="py-14">
        <div className="grid gap-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
          {columns.map((column) => (
            <nav key={column.label} aria-label={column.label}>
              <h2 className="label-caps mb-3 text-ink-subtle">{column.label}</h2>
              <ul className="flex flex-col gap-2">
                {column.links.map((link) => (
                  <li key={`${column.label}-${link.href}`}>
                    <Link
                      href={link.href}
                      className="text-sm text-ink-muted transition-colors hover:text-accent"
                    >
                      {link.label}
                    </Link>
                  </li>
                ))}
              </ul>
            </nav>
          ))}
        </div>

        <div className="mt-12 grid gap-6 border-t border-line pt-8 lg:grid-cols-[1fr_auto] lg:items-center">
          <div className="flex flex-wrap items-center gap-4">
            <div className="flex items-center gap-2 text-ink-strong">
              <BrandMark className="size-5 text-accent" />
              <span className="display-type text-md font-semibold">Foundry</span>
            </div>
            <Badge size="sm">v1.0.0</Badge>
            <Status appearance="dot" kind="operational" label="All systems operational" />
          </div>

          <div className="flex flex-wrap items-center gap-4 text-xs text-ink-subtle">
            <span className="flex items-center gap-1.5">
              <Globe className="size-3.5" aria-hidden="true" />
              English (US)
            </span>
            <span>Fictional product · demo content throughout</span>
          </div>
        </div>
      </Container>
    </footer>
  )
}

components/blocks/footers/mega.tsx

import Link from 'next/link'
import { Globe } from 'lucide-react'
import { BrandMark } from '@/components/library/brand'
import { Badge } from '@/components/ui/badge'
import { Container } from '@/components/ui/layout'
import { Status } from '@/components/ui/status'
import { productLinks, resourceLinks, companyLinks, megaMenu } from '@/content/nav-demo'

/**
 * Mega footer
 *
 * Six columns plus a status and locale strip. Appropriate for products with
 * genuinely large surface area — a mega footer over a five-page site is a
 * confession, not a feature.
 *
 * The system-status line is a real Status component so it carries an icon and
 * a word, not just a green dot.
 */
const columns = [
  { label: 'Build', links: megaMenu[0]?.links ?? [] },
  { label: 'Compose', links: megaMenu[1]?.links ?? [] },
  { label: 'Ship', links: megaMenu[2]?.links ?? [] },
  { label: 'Product', links: productLinks },
  { label: 'Resources', links: resourceLinks },
  { label: 'Company', links: companyLinks },
]

export default function MegaFooter() {
  return (
    <footer className="border-t border-line bg-surface-sunken">
      <Container size="wide" className="py-14">
        <div className="grid gap-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
          {columns.map((column) => (
            <nav key={column.label} aria-label={column.label}>
              <h2 className="label-caps mb-3 text-ink-subtle">{column.label}</h2>
              <ul className="flex flex-col gap-2">
                {column.links.map((link) => (
                  <li key={`${column.label}-${link.href}`}>
                    <Link
                      href={link.href}
                      className="text-sm text-ink-muted transition-colors hover:text-accent"
                    >
                      {link.label}
                    </Link>
                  </li>
                ))}
              </ul>
            </nav>
          ))}
        </div>

        <div className="mt-12 grid gap-6 border-t border-line pt-8 lg:grid-cols-[1fr_auto] lg:items-center">
          <div className="flex flex-wrap items-center gap-4">
            <div className="flex items-center gap-2 text-ink-strong">
              <BrandMark className="size-5 text-accent" />
              <span className="display-type text-md font-semibold">Foundry</span>
            </div>
            <Badge size="sm">v1.0.0</Badge>
            <Status appearance="dot" kind="operational" label="All systems operational" />
          </div>

          <div className="flex flex-wrap items-center gap-4 text-xs text-ink-subtle">
            <span className="flex items-center gap-1.5">
              <Globe className="size-3.5" aria-hidden="true" />
              English (US)
            </span>
            <span>Fictional product · demo content throughout</span>
          </div>
        </div>
      </Container>
    </footer>
  )
}

components/ui/status.tsx

import { CheckCircle2, AlertTriangle, XCircle, Info, CircleDashed, Clock } from 'lucide-react'
import { cn } from '@/lib/cn'

/**
 * Status
 *
 * Deliberately separate from Badge. A status describes the *state of a thing*
 * (a deployment, an invoice, a service) and therefore always pairs an icon
 * with a label — colour is the third signal, never the only one. That rule is
 * what makes the library legible to colour-blind users without a theme switch.
 */
export type StatusKind = 'operational' | 'degraded' | 'down' | 'pending' | 'info' | 'idle'

export interface StatusProps {
  kind: StatusKind
  label: string
  /** `dot` for dense tables, `pill` for standalone display. */
  appearance?: 'dot' | 'pill' | 'inline'
  className?: string
}

const config = {
  operational: {
    icon: CheckCircle2,
    text: 'text-success',
    bg: 'bg-success-soft border-success-line',
    dot: 'bg-success',
  },
  degraded: {
    icon: AlertTriangle,
    text: 'text-warning',
    bg: 'bg-warning-soft border-warning-line',
    dot: 'bg-warning',
  },
  down: {
    icon: XCircle,
    text: 'text-danger',
    bg: 'bg-danger-soft border-danger-line',
    dot: 'bg-danger',
  },
  pending: { icon: Clock, text: 'text-info', bg: 'bg-info-soft border-info-line', dot: 'bg-info' },
  info: { icon: Info, text: 'text-info', bg: 'bg-info-soft border-info-line', dot: 'bg-info' },
  idle: {
    icon: CircleDashed,
    text: 'text-ink-subtle',
    bg: 'bg-surface-sunken border-line',
    dot: 'bg-ink-subtle',
  },
} as const

export function Status({ kind, label, appearance = 'inline', className }: StatusProps) {
  const entry = config[kind]
  const Icon = entry.icon

  if (appearance === 'dot') {
    return (
      <span className={cn('inline-flex items-center gap-2 text-sm text-ink', className)}>
        <span className={cn('size-2 shrink-0 rounded-full', entry.dot)} aria-hidden="true" />
        {label}
      </span>
    )
  }

  if (appearance === 'pill') {
    return (
      <span
        className={cn(
          'inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium',
          entry.bg,
          entry.text,
          className,
        )}
      >
        <Icon className="size-3.5 shrink-0" aria-hidden="true" />
        {label}
      </span>
    )
  }

  return (
    <span
      className={cn('inline-flex items-center gap-1.5 text-sm font-medium', entry.text, className)}
    >
      <Icon className="size-4 shrink-0" aria-hidden="true" />
      {label}
    </span>
  )
}

Demo source — adapt to your project. Foundry is not published as a package.

Usage

For products with genuinely large surface area. A mega footer over a five-page site is a confession, not a feature.

  • System status belongs here — it is where people look when something is wrong.
  • Columns reflow from six to three to two to one; test at 390px before shipping.

Variants and states

Every entry below is a genuine difference in behaviour or layout, and every one of them is visible in the preview above.

  • Six columns at xl
  • Three at lg
  • Status and locale strip

Accessibility

Status semantics
Uses the Status component, so the state has an icon and a word.
Column landmarks
All six columns are individually labelled navigation regions.

Foundry implements published ARIA patterns and is tested against them. No WCAG certification is claimed — see the accessibility documentation for what is and is not covered.