{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "footer",
  "type": "registry:block",
  "title": "Footer",
  "description": "A site footer with link groups in columns, a brand area, social links and a legal line. Each link group is a separately named navigation landmark.",
  "categories": [
    "section"
  ],
  "registryDependencies": [
    "https://facadeui.dev/r/container.json",
    "https://facadeui.dev/r/heading.json",
    "https://facadeui.dev/r/types.json",
    "https://facadeui.dev/r/utils.json"
  ],
  "files": [
    {
      "path": "src/sections/footer.tsx",
      "type": "registry:component",
      "target": "components/sections/footer.tsx",
      "content": "/**\n * Footer — multi-column link groups, brand block, and a legal line.\n *\n * Degrades on purpose: with no `groups` it renders as a single simple row, which\n * is the right footer for a one-page site. Adding groups turns it into the\n * multi-column form without a second component.\n *\n * a11y: several things worth spelling out.\n *\n *  - Each column is a `<nav>` with its own accessible name taken from the column\n *    heading, so a screen reader announces \"Product navigation\" rather than\n *    meeting four unnamed navigation landmarks in a row.\n *  - Column headings are real headings at a level the caller controls, not\n *    styled `<div>`s.\n *  - Social links carry visible-to-AT names even when they show only an icon.\n *  - The copyright year is rendered by the caller, not by `new Date()`. Deriving\n *    it here would mean the server and the client can disagree across midnight,\n *    and it makes the output non-deterministic for snapshot tests.\n *\n * Dependencies: react, @/lib/types, @/lib/utils,\n * @/components/ui/container, @/components/ui/heading.\n */\n\nimport type { ElementType, ReactNode } from \"react\"\n\nimport type { HeadingLevel, IconComponent, LinkComponent } from \"@/lib/types\"\nimport { cn, slugId } from \"@/lib/utils\"\nimport { Container } from \"@/components/ui/container\"\nimport { Heading } from \"@/components/ui/heading\"\n\nexport interface FooterLink {\n  label: string\n  href: string\n  external?: boolean\n  /** Shown as a small tag beside the label — \"New\", \"Beta\". */\n  badge?: ReactNode\n}\n\nexport interface FooterGroup {\n  title: string\n  links: FooterLink[]\n}\n\nexport interface FooterSocial {\n  label: string\n  href: string\n  icon: IconComponent\n}\n\nexport interface FooterProps {\n  groups?: FooterGroup[]\n  /** Wordmark, logo, or a short pitch. */\n  brand?: ReactNode\n  /** Shown under the brand, such as a newsletter form or a status badge. */\n  children?: ReactNode\n  social?: FooterSocial[]\n  /** The full line, e.g. `© 2026 Acme, Inc.` Rendered as given. */\n  copyright?: ReactNode\n  /** Links such as privacy and terms. Shown in a row at the bottom. */\n  legal?: FooterLink[]\n  link?: LinkComponent\n  /** Heading level of the column headings. Defaults to `2`. */\n  headingLevel?: HeadingLevel\n  className?: string\n  id?: string\n}\n\nconst linkClass =\n  \"text-muted-foreground hover:text-foreground focus-visible:ring-ring inline-flex min-h-8 items-center gap-2 rounded-sm text-sm transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n\nexport function Footer({\n  groups = [],\n  brand,\n  children,\n  social = [],\n  copyright,\n  legal = [],\n  link,\n  headingLevel = 2,\n  className,\n  id,\n}: FooterProps) {\n  const Link = (link ?? \"a\") as ElementType\n\n  const renderLink = (item: FooterLink) => (\n    <li key={`${item.href}-${item.label}`}>\n      <Link\n        href={item.href}\n        {...(item.external ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n        className={linkClass}\n      >\n        {item.label}\n        {item.badge}\n        {item.external ? <span className=\"sr-only\"> (opens in a new tab)</span> : null}\n      </Link>\n    </li>\n  )\n\n  return (\n    <footer id={id} className={cn(\"border-t\", className)}>\n      <Container className=\"flex flex-col gap-12 py-14\">\n        {groups.length > 0 || brand || children ? (\n          <div\n            className={cn(\n              \"grid gap-10\",\n              groups.length > 0 &&\n                \"lg:grid-cols-[minmax(0,1.5fr)_minmax(0,3fr)] lg:gap-16\",\n            )}\n          >\n            {brand || children ? (\n              <div className=\"flex max-w-sm flex-col gap-4\">\n                {brand}\n                {children}\n              </div>\n            ) : null}\n\n            {groups.length > 0 ? (\n              <div\n                className={cn(\n                  \"grid gap-10 sm:gap-8\",\n                  groups.length >= 4 ? \"sm:grid-cols-2 md:grid-cols-4\" : \"sm:grid-cols-3\",\n                )}\n              >\n                {groups.map((group) => {\n                  const groupId = slugId(group.title, \"footer\")\n                  return (\n                    // Naming each column stops the footer from contributing a\n                    // run of indistinguishable navigation landmarks.\n                    <nav\n                      key={group.title}\n                      aria-labelledby={groupId}\n                      className=\"flex flex-col gap-4\"\n                    >\n                      <Heading\n                        level={headingLevel}\n                        id={groupId}\n                        className=\"text-foreground text-sm font-semibold\"\n                      >\n                        {group.title}\n                      </Heading>\n                      <ul className=\"flex flex-col gap-2.5\">\n                        {group.links.map(renderLink)}\n                      </ul>\n                    </nav>\n                  )\n                })}\n              </div>\n            ) : null}\n          </div>\n        ) : null}\n\n        <div className=\"border-border flex flex-col-reverse gap-6 border-t pt-8 sm:flex-row sm:items-center sm:justify-between\">\n          <div className=\"text-muted-foreground flex flex-wrap items-center gap-x-6 gap-y-2 text-sm\">\n            {copyright ? <p>{copyright}</p> : null}\n            {legal.length > 0 ? (\n              <ul className=\"flex flex-wrap items-center gap-x-6 gap-y-2\">\n                {legal.map(renderLink)}\n              </ul>\n            ) : null}\n          </div>\n\n          {social.length > 0 ? (\n            <ul className=\"flex items-center gap-1\">\n              {social.map((item) => {\n                const Icon = item.icon as ElementType\n                return (\n                  <li key={item.href}>\n                    <Link\n                      href={item.href}\n                      target=\"_blank\"\n                      rel=\"noopener noreferrer\"\n                      className=\"text-muted-foreground hover:text-foreground hover:bg-accent focus-visible:ring-ring inline-flex size-11 items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2\"\n                    >\n                      <Icon aria-hidden focusable=\"false\" className=\"size-5\" />\n                      <span className=\"sr-only\">{item.label} (opens in a new tab)</span>\n                    </Link>\n                  </li>\n                )\n              })}\n            </ul>\n          ) : null}\n        </div>\n      </Container>\n    </footer>\n  )\n}\n"
    }
  ],
  "docs": "Import styles/facade-tokens.css in your global stylesheet, after @import \"tailwindcss\". Set headingLevel to fit the page outline (sections default to h2). Pass next/link and next/image through the link and image props. Docs: https://facadeui.dev/components/footer"
}
