Docs
Multi-Column Footer

Multi-Column Footer

A comprehensive footer with multiple link columns, newsletter signup, and social links. Clean design with flexible layout options.

Features

  • Multi-column layout - Up to 4 link columns
  • Newsletter signup - Built-in email capture
  • Social media icons - Twitter, GitHub, LinkedIn, Facebook, Instagram
  • Responsive grid - Adapts from 4 to 1 column
  • Bottom links - Legal and additional links
  • Custom copyright - Personalize your copyright text
  • Loading states - Newsletter submission feedback
  • Success animation - Confirmation on subscribe
  • Clean design - Modern with solid colors
  • TypeScript support - Full type safety

Installation

Copy and paste the following code into your project.

"use client";
 
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Facebook, Github, Instagram, Linkedin, Twitter } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
 
interface FooterLink {
  label: string;
  href: string;
}
 
interface FooterColumn {
  title: string;
  links: FooterLink[];
}
 
interface SocialLink {
  icon: "twitter" | "facebook" | "instagram" | "linkedin" | "github";
  href: string;
  label: string;
}
 
interface FooterMultiColumnProps {
  companyName: string;
  description?: string;
  columns: FooterColumn[];
  socialLinks?: SocialLink[];
  showNewsletter?: boolean;
  newsletterTitle?: string;
  newsletterDescription?: string;
  onNewsletterSubmit?: (email: string) => Promise<void> | void;
  bottomLinks?: FooterLink[];
  copyrightText?: string;
}
 
const socialIcons = {
  twitter: Twitter,
  facebook: Facebook,
  instagram: Instagram,
  linkedin: Linkedin,
  github: Github,
};
 
export function FooterMultiColumn({
  companyName,
  description,
  columns,
  socialLinks,
  showNewsletter = true,
  newsletterTitle = "Subscribe to our newsletter",
  newsletterDescription = "Get the latest updates and news.",
  onNewsletterSubmit,
  bottomLinks,
  copyrightText,
}: FooterMultiColumnProps) {
  const [email, setEmail] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [isSuccess, setIsSuccess] = useState(false);
 
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (email && onNewsletterSubmit) {
      setIsLoading(true);
      try {
        await onNewsletterSubmit(email);
        setIsSuccess(true);
        setEmail("");
        setTimeout(() => setIsSuccess(false), 3000);
      } catch (error) {
        console.error("Newsletter signup error:", error);
      } finally {
        setIsLoading(false);
      }
    }
  };
 
  return (
    <footer className="z-30 border-t border-gray-200 bg-white dark:border-zinc-800 dark:bg-black">
      <div className="container mx-auto px-6 py-12 lg:py-16">
        <div className="grid gap-8 lg:grid-cols-12 lg:gap-12">
          <div className="lg:col-span-4">
            <Link href="/" className="inline-block">
              <span className="text-2xl font-bold text-gray-900 dark:text-white">
                {companyName}
              </span>
            </Link>
            {description && (
              <p className="mt-4 text-sm text-gray-600 dark:text-zinc-400">
                {description}
              </p>
            )}
 
            {showNewsletter && (
              <div className="mt-6">
                <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
                  {newsletterTitle}
                </h3>
                <p className="mt-2 text-sm text-gray-600 dark:text-zinc-400">
                  {newsletterDescription}
                </p>
                <form onSubmit={handleSubmit} className="mt-4 space-y-3">
                  <Input
                    type="email"
                    placeholder="Enter your email"
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    required
                    disabled={isLoading || isSuccess}
                    className="h-10 text-sm dark:border-zinc-800 dark:bg-zinc-900 dark:text-white dark:placeholder:text-zinc-500"
                  />
                  <Button
                    type="submit"
                    disabled={isLoading || isSuccess}
                    className="h-10 w-full bg-gray-900 text-sm font-medium text-white hover:bg-gray-800 dark:bg-white dark:text-black dark:hover:bg-zinc-200"
                  >
                    {isSuccess ? "Subscribed!" : "Subscribe"}
                  </Button>
                </form>
              </div>
            )}
          </div>
 
          <div className="grid grid-cols-2 gap-8 sm:grid-cols-3 lg:col-span-8 lg:grid-cols-4">
            {columns.map((column, index) => (
              <div key={index}>
                <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
                  {column.title}
                </h3>
                <ul className="mt-4 space-y-3">
                  {column.links.map((link, linkIndex) => (
                    <li key={linkIndex}>
                      <Link
                        href={link.href}
                        className="text-sm text-gray-600 transition-colors hover:text-gray-900 dark:text-zinc-400 dark:hover:text-white"
                      >
                        {link.label}
                      </Link>
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </div>
 
        <div className="mt-12 border-t border-gray-200 pt-8 dark:border-zinc-800">
          <div className="flex flex-col items-center justify-between gap-4 sm:flex-row">
            <p className="text-sm text-gray-600 dark:text-zinc-400">
              {copyrightText ||
                `© ${new Date().getFullYear()} ${companyName}. All rights reserved.`}
            </p>
 
            {bottomLinks && bottomLinks.length > 0 && (
              <div className="flex flex-wrap items-center gap-6">
                {bottomLinks.map((link, index) => (
                  <Link
                    key={index}
                    href={link.href}
                    className="text-sm text-gray-600 transition-colors hover:text-gray-900 dark:text-zinc-400 dark:hover:text-white"
                  >
                    {link.label}
                  </Link>
                ))}
              </div>
            )}
 
            {socialLinks && socialLinks.length > 0 && (
              <div className="flex items-center gap-4">
                {socialLinks.map((social, index) => {
                  const Icon = socialIcons[social.icon];
                  return (
                    <Link
                      key={index}
                      href={social.href}
                      aria-label={social.label}
                      className="text-gray-600 transition-colors hover:text-gray-900 dark:text-zinc-400 dark:hover:text-white"
                    >
                      <Icon className="h-5 w-5" />
                    </Link>
                  );
                })}
              </div>
            )}
          </div>
        </div>
      </div>
    </footer>
  );
}

Update the import paths to match your project setup.

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";

Usage

Basic Usage

import FooterMultiColumn from "@/components/ui/footer-multi-column";
 
export default function Layout({ children }) {
    return (
        <>
            {children}
            <FooterMultiColumn
                companyName="Acme Inc"
                description="Building amazing products."
                columns={[
                    {
                        title: "Product",
                        links: [
                            { label: "Features", href: "/features" },
                            { label: "Pricing", href: "/pricing" },
                        ],
                    },
                ]}
                onNewsletterSubmit={(email) => console.log("Subscribed:", email)}
            />
        </>
    );
}

Complete Example

<FooterMultiColumn
    companyName="Acme Inc"
    description="Building amazing products for the modern web."
    columns={[
        {
            title: "Product",
            links: [
                { label: "Features", href: "/features" },
                { label: "Pricing", href: "/pricing" },
                { label: "Integrations", href: "/integrations" },
                { label: "Changelog", href: "/changelog" },
            ],
        },
        {
            title: "Company",
            links: [
                { label: "About", href: "/about" },
                { label: "Blog", href: "/blog" },
                { label: "Careers", href: "/careers" },
                { label: "Contact", href: "/contact" },
            ],
        },
        {
            title: "Resources",
            links: [
                { label: "Documentation", href: "/docs" },
                { label: "Help Center", href: "/help" },
                { label: "Community", href: "/community" },
                { label: "Status", href: "/status" },
            ],
        },
    ]}
    socialLinks={[
        { icon: "twitter", href: "#", label: "Twitter" },
        { icon: "github", href: "#", label: "GitHub" },
        { icon: "linkedin", href: "#", label: "LinkedIn" },
    ]}
    bottomLinks={[
        { label: "Privacy Policy", href: "/privacy" },
        { label: "Terms of Service", href: "/terms" },
    ]}
    onNewsletterSubmit={(email) => console.log(email)}
/>

Props

PropTypeDefaultDescription
companyNamestringRequiredCompany name
descriptionstringundefinedCompany description
columnsFooterColumn[]RequiredLink columns
socialLinksSocialLink[]undefinedSocial media links
showNewsletterbooleantrueShow newsletter signup
newsletterTitlestring"Subscribe to our newsletter"Newsletter title
newsletterDescriptionstring"Get the latest updates and news."Newsletter description
onNewsletterSubmit(email: string) => voidundefinedNewsletter submit handler
bottomLinksFooterLink[]undefinedBottom row links
copyrightTextstringAuto-generatedCustom copyright text

TypeScript Interface

interface FooterMultiColumnProps {
    companyName: string;
    description?: string;
    columns: FooterColumn[];
    socialLinks?: SocialLink[];
    showNewsletter?: boolean;
    newsletterTitle?: string;
    newsletterDescription?: string;
    onNewsletterSubmit?: (email: string) => Promise<void> | void;
    bottomLinks?: FooterLink[];
    copyrightText?: string;
}
 
interface FooterLink {
    label: string;
    href: string;
}
 
interface FooterColumn {
    title: string;
    links: FooterLink[];
}
 
interface SocialLink {
    icon: "twitter" | "facebook" | "instagram" | "linkedin" | "github";
    href: string;
    label: string;
}

Without Newsletter

<FooterMultiColumn
    companyName="Acme Inc"
    showNewsletter={false}
    columns={[
        {
            title: "Product",
            links: [
                { label: "Features", href: "/features" },
                { label: "Pricing", href: "/pricing" },
            ],
        },
    ]}
    socialLinks={[
        { icon: "twitter", href: "#", label: "Twitter" },
        { icon: "github", href: "#", label: "GitHub" },
    ]}
/>
<FooterMultiColumn
    companyName="Acme Inc"
    description="Simple and elegant."
    columns={[
        {
            title: "Links",
            links: [
                { label: "About", href: "/about" },
                { label: "Contact", href: "/contact" },
            ],
        },
    ]}
    showNewsletter={false}
/>

Custom Newsletter Text

<FooterMultiColumn
    companyName="Acme Inc"
    newsletterTitle="Stay in the loop"
    newsletterDescription="Weekly updates on new features."
    columns={[...]}
    onNewsletterSubmit={(email) => console.log(email)}
/>

All Social Icons

<FooterMultiColumn
    companyName="Acme Inc"
    columns={[...]}
    socialLinks={[
        { icon: "twitter", href: "#", label: "Twitter" },
        { icon: "facebook", href: "#", label: "Facebook" },
        { icon: "instagram", href: "#", label: "Instagram" },
        { icon: "linkedin", href: "#", label: "LinkedIn" },
        { icon: "github", href: "#", label: "GitHub" },
    ]}
/>
<FooterMultiColumn
    companyName="Acme Inc"
    copyrightText="© 2024 Acme Inc. Made with ❤️"
    columns={[...]}
/>

With API Integration

"use client";
 
import FooterMultiColumn from "@/components/ui/footer-multi-column";
 
export default function Layout({ children }) {
    const handleNewsletterSubmit = async (email: string) => {
        try {
            const response = await fetch("/api/newsletter", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ email }),
            });
 
            if (response.ok) {
                alert("Successfully subscribed!");
            }
        } catch (error) {
            console.error("Subscription failed:", error);
        }
    };
 
    return (
        <>
            {children}
            <FooterMultiColumn
                companyName="Acme Inc"
                columns={[...]}
                onNewsletterSubmit={handleNewsletterSubmit}
            />
        </>
    );
}