mdxui

Footer Component

Site footer with logo, links, social media, and legal information

Footer Component

The <Footer> component provides the site footer with logo, link groups, social media links, copyright, and optional status indicator.

Interface

import type { FooterProps } from 'mdxui'

interface FooterLinkGroup {
  title: string
  links: Array<{
    label: string
    href: string
  }>
}

interface FooterProps {
  /** Logo element */
  logo: ReactNode
  /** Footer link groups */
  links: FooterLinkGroup[]
  /** Social media links */
  social?: Array<{
    platform: string
    href: string
    icon?: ReactNode
  }>
  /** Copyright text */
  copyright?: string
}

Usage

Basic Example

import { Footer } from '@mdxui/beacon'

<Footer
  logo={<Logo />}
  companyName="Acme Inc"
  linkGroups={[
    {
      group: "Product",
      items: [
        { title: "Features", href: "/features" },
        { title: "Pricing", href: "/pricing" },
        { title: "Security", href: "/security" },
      ]
    },
    {
      group: "Company",
      items: [
        { title: "About", href: "/about" },
        { title: "Blog", href: "/blog" },
        { title: "Careers", href: "/careers" },
      ]
    },
  ]}
  socialLinks={[
    { name: "Twitter", href: "https://twitter.com/acme", icon: <Twitter /> },
    { name: "GitHub", href: "https://github.com/acme", icon: <GitHub /> },
  ]}
/>

With Description

<Footer
  logo={<Logo />}
  description="The fastest way to build modern web applications."
  companyName="Acme Inc"
  linkGroups={footerLinks}
/>

With Status Indicator

<Footer
  logo={<Logo />}
  companyName="Acme Inc"
  linkGroups={footerLinks}
  statusText="All Systems Normal"
  showStatus={true}
/>

Props

logo (required)

Type: ReactNode

Logo element displayed in the footer.

<Footer logo={<Logo variant="light" />} />

description (optional)

Type: string

Description text displayed below the logo.

<Footer
  logo={<Logo />}
  description="Building the future of web development."
/>

companyName (required)

Type: string

Company name used in the copyright notice.

<Footer companyName="Acme Inc" />
// Renders: © 2024 Acme Inc, All rights reserved

linkGroups (optional)

Type: FooterLinkGroup[]

Array of link groups organized into columns.

interface FooterLinkGroup {
  group: string      // Column title
  items: FooterLink[]
}

interface FooterLink {
  title: string      // Link text
  href: string       // Link URL
}

<Footer
  linkGroups={[
    {
      group: "Product",
      items: [
        { title: "Features", href: "/features" },
        { title: "Pricing", href: "/pricing" },
        { title: "Security", href: "/security" },
        { title: "Changelog", href: "/changelog" },
      ]
    },
    {
      group: "Resources",
      items: [
        { title: "Documentation", href: "/docs" },
        { title: "API Reference", href: "/docs/api" },
        { title: "Guides", href: "/guides" },
        { title: "Blog", href: "/blog" },
      ]
    },
    {
      group: "Company",
      items: [
        { title: "About", href: "/about" },
        { title: "Careers", href: "/careers" },
        { title: "Contact", href: "/contact" },
        { title: "Partners", href: "/partners" },
      ]
    },
    {
      group: "Legal",
      items: [
        { title: "Privacy", href: "/privacy" },
        { title: "Terms", href: "/terms" },
        { title: "Security", href: "/security" },
      ]
    },
  ]}
/>

Type: SocialLink[]

Array of social media links with icons.

interface SocialLink {
  name: string        // Platform name (for aria-label)
  href: string        // Social profile URL
  icon: ReactNode     // Icon component
}

import { Twitter, GitHub, LinkedIn } from 'lucide-react'

<Footer
  socialLinks={[
    {
      name: "Twitter",
      href: "https://twitter.com/acme",
      icon: <Twitter className="size-5" />
    },
    {
      name: "GitHub",
      href: "https://github.com/acme",
      icon: <GitHub className="size-5" />
    },
    {
      name: "LinkedIn",
      href: "https://linkedin.com/company/acme",
      icon: <LinkedIn className="size-5" />
    },
  ]}
/>

statusText (optional)

Type: string Default: "All Systems Normal"

Status text displayed in the bottom right (e.g., system status).

<Footer statusText="All Systems Operational" />

showStatus (optional)

Type: boolean Default: true

Whether to display the status indicator.

<Footer showStatus={true} />

LinkComponent (optional)

Type: ComponentType<FooterLinkComponentProps>

Custom link component for routing (e.g., Next.js Link).

import Link from 'next/link'

<Footer LinkComponent={Link} />

className (optional)

Type: string

Additional CSS classes for custom styling.

<Footer className="bg-slate-900 text-white" />

Implementation Details

The reference implementation from @mdxui/beacon includes:

Structure

<footer className="bg-background border-t py-8 sm:py-16 lg:pt-32">
  <div className="container max-w-5xl">
    {/* Main Grid */}
    <div className="grid gap-12 md:grid-cols-5">
      {/* Logo + Description (2 columns) */}
      <div className="md:col-span-2">
        <LinkComponent href="/">
          {logo}
        </LinkComponent>
        {description && (
          <p className="text-muted-foreground">{description}</p>
        )}
      </div>

      {/* Link Groups (3 columns) */}
      <div className="col-span-3 grid gap-6 sm:grid-cols-3">
        {linkGroups.map(group => (
          <div key={group.group}>
            <span className="font-medium">{group.group}</span>
            <div className="flex flex-col gap-4">
              {group.items.map(link => (
                <LinkComponent href={link.href}>
                  {link.title}
                </LinkComponent>
              ))}
            </div>
          </div>
        ))}

        {/* Social Links */}
        {socialLinks.length > 0 && (
          <div>
            <span className="font-medium">Community</span>
            <div className="flex gap-3">
              {socialLinks.map(social => (
                <LinkComponent
                  href={social.href}
                  target="_blank"
                  rel="noopener noreferrer"
                  aria-label={social.name}
                >
                  {social.icon}
                </LinkComponent>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>

    {/* Divider */}
    <div className="h-px bg-foreground/10" />

    {/* Bottom Row: Copyright + Status */}
    <div className="flex justify-between">
      <span className="text-muted-foreground text-sm">
        © {new Date().getFullYear()} {companyName}, All rights reserved
      </span>
      {showStatus && (
        <span className="text-sm text-emerald-500">{statusText}</span>
      )}
    </div>
  </div>
</footer>

Responsive Layout

  • Mobile: Single column, stacked layout
  • Tablet: 2-3 column grid for link groups
  • Desktop: 5 column grid (logo takes 2, links take 3)

Spacing

  • Top padding scales from py-8 (mobile) to lg:pt-32 (desktop)
  • Consistent gap between columns (gap-6 to gap-12)

Real-World Examples

const marketingFooter = {
  linkGroups: [
    {
      group: "Product",
      items: [
        { title: "Features", href: "/features" },
        { title: "Pricing", href: "/pricing" },
        { title: "Customers", href: "/customers" },
        { title: "Integrations", href: "/integrations" },
      ]
    },
    {
      group: "Developers",
      items: [
        { title: "Documentation", href: "/docs" },
        { title: "API Reference", href: "/docs/api" },
        { title: "SDKs", href: "/sdks" },
        { title: "Status", href: "/status" },
      ]
    },
    {
      group: "Company",
      items: [
        { title: "About", href: "/about" },
        { title: "Blog", href: "/blog" },
        { title: "Careers", href: "/careers" },
        { title: "Contact", href: "/contact" },
      ]
    },
  ],
  socialLinks: [
    { name: "Twitter", href: "https://twitter.com/acme", icon: <Twitter /> },
    { name: "GitHub", href: "https://github.com/acme", icon: <GitHub /> },
    { name: "Discord", href: "https://discord.gg/acme", icon: <MessageCircle /> },
  ]
}

<Footer
  logo={<Logo />}
  description="Build better products, faster."
  companyName="Acme Inc"
  {...marketingFooter}
  statusText="All Systems Normal"
/>
<Footer
  logo={<Logo />}
  companyName="Acme"
  linkGroups={[
    {
      group: "Documentation",
      items: [
        { title: "Getting Started", href: "/docs" },
        { title: "API Reference", href: "/docs/api" },
        { title: "Examples", href: "/examples" },
      ]
    },
    {
      group: "Community",
      items: [
        { title: "GitHub", href: "https://github.com/acme" },
        { title: "Discord", href: "https://discord.gg/acme" },
        { title: "Twitter", href: "https://twitter.com/acme" },
      ]
    },
  ]}
  showStatus={false}
/>
<Footer
  logo={<Logo />}
  companyName="Acme Inc"
  linkGroups={[
    {
      group: "Legal",
      items: [
        { title: "Privacy", href: "/privacy" },
        { title: "Terms", href: "/terms" },
      ]
    },
  ]}
  showStatus={false}
/>

Accessibility

The reference implementation includes:

  • Semantic HTML - Uses <footer> element
  • Link Attributes - External links have target="_blank" and rel="noopener noreferrer"
  • ARIA Labels - Social links include aria-label with platform name
  • Color Contrast - Muted text meets WCAG AA standards
  • Focus Indicators - Visible focus states on all links
<LinkComponent
  href={social.href}
  target="_blank"
  rel="noopener noreferrer"
  aria-label={social.name}
>
  {social.icon}
</LinkComponent>

Composition with Site

The <Footer> component is typically rendered by <Site>:

<Site name="Acme">
  {/* Site automatically renders Footer */}
  <LandingPage>...</LandingPage>
</Site>

How it works:

  1. The <Site> component includes <Footer> automatically
  2. Footer props are configured in the template implementation
  3. Logo is inherited from <Site> component

TypeScript

Full type definitions:

import type { ReactNode, ComponentType } from 'react'
import type { z } from 'zod'

export const FooterLinkGroupSchema = z.object({
  title: z.string(),
  links: z.array(z.object({
    label: z.string(),
    href: z.string(),
  })),
})

export const FooterPropsSchema = z.object({
  logo: z.any(),
  links: z.array(FooterLinkGroupSchema),
  social: z.array(z.object({
    platform: z.string(),
    href: z.string(),
    icon: z.any().optional(),
  })).optional(),
  copyright: z.string().optional(),
})

export type FooterLinkGroup = z.infer<typeof FooterLinkGroupSchema>
export type FooterProps = z.infer<typeof FooterPropsSchema>
export type Footer = Component<FooterProps>

Reference Implementation Types:

// From @mdxui/beacon
export interface FooterLink {
  title: string
  href: string
}

export interface FooterLinkGroup {
  group: string
  items: FooterLink[]
}

export interface SocialLink {
  name: string
  href: string
  icon: ReactNode
}

export interface FooterProps {
  logo: ReactNode
  description?: string
  companyName: string
  linkGroups?: FooterLinkGroup[]
  socialLinks?: SocialLink[]
  statusText?: string
  showStatus?: boolean
  LinkComponent?: ComponentType<FooterLinkComponentProps>
  className?: string
}

On this page