Footer

Footer 01 — Mega Footer

Mega footer with logo, tagline, newsletter signup form, four link columns, social icons and a primary glow accent.

$ npx shadcn@latest add @ludusvibe/footer-01
Open in v0

Code

Installed to components/sections/footer-01.tsx — it's yours to edit.

"use client"

import * as React from "react"

import { buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Reveal } from "@/components/ludus/reveal"
import { cn } from "@/lib/utils"

function XIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden {...props}>
      <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231 5.45-6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117l11.966 15.644Z" />
    </svg>
  )
}

function GitHubIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden {...props}>
      <path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.55 0-.27-.01-1.17-.02-2.12-3.2.7-3.87-1.36-3.87-1.36-.52-1.33-1.28-1.68-1.28-1.68-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.19 1.76 1.19 1.03 1.75 2.69 1.25 3.35.95.1-.75.4-1.25.72-1.54-2.55-.29-5.23-1.28-5.23-5.68 0-1.26.45-2.28 1.19-3.09-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.18 1.18a11.1 11.1 0 0 1 5.8 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.11 3.05.74.81 1.19 1.83 1.19 3.09 0 4.41-2.69 5.38-5.25 5.66.41.36.78 1.05.78 2.12 0 1.53-.01 2.76-.01 3.14 0 .3.2.66.8.55A11.51 11.51 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5Z" />
    </svg>
  )
}

function LinkedInIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden {...props}>
      <path d="M20.45 20.45h-3.55v-5.57c0-1.33-.03-3.04-1.85-3.04-1.86 0-2.14 1.45-2.14 2.94v5.67H9.35V9h3.41v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.46v6.28ZM5.34 7.43a2.06 2.06 0 1 1 0-4.12 2.06 2.06 0 0 1 0 4.12ZM7.12 20.45H3.56V9h3.56v11.45ZM22.22 0H1.77C.79 0 0 .77 0 1.72v20.55C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.73V1.72C24 .77 23.2 0 22.22 0Z" />
    </svg>
  )
}

function YouTubeIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden {...props}>
      <path d="M23.5 6.19a3.02 3.02 0 0 0-2.12-2.14C19.5 3.55 12 3.55 12 3.55s-7.5 0-9.38.5A3.02 3.02 0 0 0 .5 6.19C0 8.07 0 12 0 12s0 3.93.5 5.81a3.02 3.02 0 0 0 2.12 2.14c1.88.5 9.38.5 9.38.5s7.5 0 9.38-.5a3.02 3.02 0 0 0 2.12-2.14C24 15.93 24 12 24 12s0-3.93-.5-5.81ZM9.55 15.57V8.43L15.82 12l-6.27 3.57Z" />
    </svg>
  )
}

type FooterLink = { label: string; href: string }
type FooterColumn = { title: string; links: FooterLink[] }
type SocialLink = { label: string; href: string; icon: React.ReactNode }

export type Footer01Props = {
  /** Text logo — pass a string or any node. */
  logo?: React.ReactNode
  logoHref?: string
  tagline?: string
  newsletterTitle?: string
  newsletterDescription?: string
  newsletterPlaceholder?: string
  newsletterCta?: string
  columns?: FooterColumn[]
  socialLinks?: SocialLink[]
  copyright?: string
  className?: string
}

export function Footer01({
  logo = "Lumen",
  logoHref = "#",
  tagline = "Production-ready landing page sections that drop into your codebase and inherit your brand automatically.",
  newsletterTitle = "Stay in the loop",
  newsletterDescription = "One email a month with new sections and updates. Unsubscribe anytime.",
  newsletterPlaceholder = "Enter your email",
  newsletterCta = "Subscribe",
  columns = [
    {
      title: "Product",
      links: [
        { label: "Features", href: "#" },
        { label: "Pricing", href: "#" },
        { label: "Changelog", href: "#" },
        { label: "Roadmap", href: "#" },
      ],
    },
    {
      title: "Company",
      links: [
        { label: "About", href: "#" },
        { label: "Blog", href: "#" },
        { label: "Careers", href: "#" },
        { label: "Contact", href: "#" },
      ],
    },
    {
      title: "Resources",
      links: [
        { label: "Documentation", href: "#" },
        { label: "Community", href: "#" },
        { label: "Templates", href: "#" },
        { label: "Support", href: "#" },
      ],
    },
    {
      title: "Legal",
      links: [
        { label: "Privacy", href: "#" },
        { label: "Terms", href: "#" },
        { label: "Security", href: "#" },
      ],
    },
  ],
  socialLinks = [
    { label: "X", href: "#", icon: <XIcon /> },
    { label: "GitHub", href: "#", icon: <GitHubIcon /> },
    { label: "LinkedIn", href: "#", icon: <LinkedInIcon /> },
    { label: "YouTube", href: "#", icon: <YouTubeIcon /> },
  ],
  copyright = `© ${new Date().getFullYear()} Lumen, Inc. All rights reserved.`,
  className,
}: Footer01Props) {
  const inputId = React.useId()

  return (
    <footer
      className={cn("relative overflow-hidden border-t bg-background", className)}
    >
      <div
        aria-hidden
        className="absolute -top-32 left-1/2 h-64 w-[640px] -translate-x-1/2 rounded-full bg-primary/10 blur-[120px]"
      />

      <div className="relative mx-auto max-w-6xl px-6 pt-16 pb-10 md:pt-20">
        <div className="grid gap-12 lg:grid-cols-[1fr_1.3fr] lg:gap-20">
          <Reveal>
            <a
              href={logoHref}
              className="inline-flex items-center gap-2.5 font-heading text-lg font-semibold tracking-tight"
            >
              <span
                aria-hidden
                className="size-4 rounded-full bg-gradient-to-br from-primary to-primary/40 ring-4 ring-primary/15"
              />
              {logo}
            </a>
            <p className="mt-4 max-w-sm text-sm text-pretty text-muted-foreground">
              {tagline}
            </p>

            <p className="mt-8 text-sm font-medium">{newsletterTitle}</p>
            <form className="mt-3 flex w-full max-w-sm gap-2">
              <label htmlFor={inputId} className="sr-only">
                Email address
              </label>
              <Input
                id={inputId}
                type="email"
                required
                placeholder={newsletterPlaceholder}
              />
              <button type="submit" className={buttonVariants()}>
                {newsletterCta}
              </button>
            </form>
            <p className="mt-2.5 text-xs text-muted-foreground">
              {newsletterDescription}
            </p>
          </Reveal>

          <div className="grid grid-cols-2 gap-x-8 gap-y-10 sm:grid-cols-4">
            {columns.map((column, i) => (
              <Reveal key={column.title} delay={0.05 * (i + 1)}>
                <p className="text-sm font-medium">{column.title}</p>
                <ul className="mt-4 space-y-3">
                  {column.links.map((link) => (
                    <li key={link.label}>
                      <a
                        href={link.href}
                        className="text-sm text-muted-foreground transition-colors hover:text-foreground"
                      >
                        {link.label}
                      </a>
                    </li>
                  ))}
                </ul>
              </Reveal>
            ))}
          </div>
        </div>

        <div className="mt-16 flex flex-col-reverse items-center justify-between gap-4 border-t pt-8 sm:flex-row">
          <p className="text-sm text-muted-foreground">{copyright}</p>
          <div className="flex items-center gap-1">
            {socialLinks.map((social) => (
              <a
                key={social.label}
                href={social.href}
                aria-label={social.label}
                className={cn(
                  buttonVariants({ variant: "ghost", size: "icon-sm" }),
                  "rounded-full text-muted-foreground hover:text-foreground"
                )}
              >
                {social.icon}
              </a>
            ))}
          </div>
        </div>
      </div>
    </footer>
  )
}