A well-structured footer serves as secondary navigation and reinforces your site's information architecture. Here is how to build one that works across all screen sizes.
Step 1: Define Footer Data
// lib/footer-data.ts
export const footerLinks = [
{
title: "Services",
links: [
{ label: "Web Design", href: "/services/web-design" },
{ label: "Web Development", href: "/services/web-development" },
{ label: "Software Development", href: "/services/software-development" },
{ label: "Mobile App Development", href: "/services/mobile-app-development" },
{ label: "UI/UX Design", href: "/services/ui-ux-design" },
{ label: "E-commerce", href: "/services/ecommerce" },
],
},
{
title: "Industries",
links: [
{ label: "Restaurants", href: "/industries/restaurant" },
{ label: "Real Estate", href: "/industries/real-estate" },
{ label: "Healthcare", href: "/industries/healthcare" },
{ label: "SaaS", href: "/industries/saas-startup" },
{ label: "E-commerce", href: "/industries/ecommerce" },
{ label: "View All", href: "/industries" },
],
},
{
title: "Company",
links: [
{ label: "About", href: "/about" },
{ label: "Blog", href: "/blog" },
{ label: "Pricing", href: "/pricing" },
{ label: "Contact", href: "/contact" },
{ label: "Demos", href: "/demos" },
],
},
{
title: "Resources",
links: [
{ label: "Tutorials", href: "/blog/tutorials" },
{ label: "Case Studies", href: "/blog/case-studies" },
{ label: "Industry Guides", href: "/blog/industry-guides" },
{ label: "Comparisons", href: "/blog/comparisons" },
],
},
];
export const socialLinks = [
{ label: "Twitter", href: "https://twitter.com/example", icon: "twitter" },
{ label: "GitHub", href: "https://github.com/example", icon: "github" },
{ label: "LinkedIn", href: "https://linkedin.com/company/example", icon: "linkedin" },
];
Step 2: Build the Footer Component
import Link from "next/link";
import { footerLinks, socialLinks } from "@/lib/footer-data";
export function Footer() {
return (
<footer className="border-t bg-gray-50 dark:border-gray-800 dark:bg-gray-950">
<div className="mx-auto max-w-7xl px-6 py-12 lg:py-16">
{/* Top section: brand + link columns */}
<div className="grid gap-8 lg:grid-cols-6">
{/* Brand column */}
<div className="lg:col-span-2">
<Link href="/" className="text-xl font-bold">
YourBrand
</Link>
<p className="mt-4 max-w-xs text-sm text-gray-500 dark:text-gray-400">
We design and develop websites, web applications, and mobile apps
that help businesses grow.
</p>
{/* Social links */}
<div className="mt-6 flex gap-4">
{socialLinks.map((social) => (
<a
key={social.label}
href={social.href}
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
aria-label={social.label}
>
<SocialIcon name={social.icon} />
</a>
))}
</div>
</div>
{/* Link columns */}
{footerLinks.map((column) => (
<div key={column.title}>
<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) => (
<li key={link.href}>
<Link
href={link.href}
className="text-sm text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
{link.label}
</Link>
</li>
))}
</ul>
</div>
))}
</div>
{/* Newsletter section */}
<div className="mt-12 border-t pt-8 dark:border-gray-800">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-white">
Subscribe to our newsletter
</h3>
<p className="mt-1 text-sm text-gray-500">
Get the latest articles and resources delivered to your inbox.
</p>
</div>
<form className="flex gap-2" onSubmit={(e) => e.preventDefault()}>
<input
type="email"
placeholder="Enter your email"
required
className="w-full rounded-lg border px-3 py-2 text-sm sm:w-64 dark:border-gray-700 dark:bg-gray-800"
/>
<button
type="submit"
className="whitespace-nowrap rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
>
Subscribe
</button>
</form>
</div>
</div>
{/* Bottom bar */}
<div className="mt-8 flex flex-col items-center justify-between gap-4 border-t pt-8 text-sm text-gray-400 dark:border-gray-800 sm:flex-row">
<p>© {new Date().getFullYear()} YourBrand. All rights reserved.</p>
<div className="flex gap-6">
<Link href="/privacy" className="hover:text-gray-600 dark:hover:text-gray-300">
Privacy Policy
</Link>
<Link href="/terms" className="hover:text-gray-600 dark:hover:text-gray-300">
Terms of Service
</Link>
<Link href="/sitemap.xml" className="hover:text-gray-600 dark:hover:text-gray-300">
Sitemap
</Link>
</div>
</div>
</div>
</footer>
);
}
Step 3: Social Icons Component
function SocialIcon({ name }: { name: string }) {
const icons: Record<string, React.ReactNode> = {
twitter: (
<svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<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.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
),
github: (
<svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<path
fillRule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clipRule="evenodd"
/>
</svg>
),
linkedin: (
<svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
),
};
return icons[name] || null;
}
Step 4: Mobile-First Responsive Behavior
The footer naturally stacks on mobile because we use grid gap-8 lg:grid-cols-6:
- Mobile: Single column, all sections stacked vertically
- Tablet (lg): 6-column grid with brand taking 2 columns, links each taking 1
For very narrow screens, you can make link columns collapsible:
"use client";
import { useState } from "react";
function CollapsibleColumn({ title, links }: { title: string; links: { label: string; href: string }[] }) {
const [open, setOpen] = useState(false);
return (
<div className="lg:hidden">
<button
onClick={() => setOpen(!open)}
className="flex w-full items-center justify-between py-3"
>
<h3 className="text-sm font-semibold">{title}</h3>
<svg
className={`h-4 w-4 transition-transform ${open ? "rotate-180" : ""}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{open && (
<ul className="space-y-2 pb-4">
{links.map((link) => (
<li key={link.href}>
<a href={link.href} className="text-sm text-gray-500">
{link.label}
</a>
</li>
))}
</ul>
)}
</div>
);
}
SEO Benefits
A well-structured footer with organized links:
- Improves internal linking and crawlability
- Helps distribute PageRank across your site
- Provides quick access to important pages
- Reinforces your site structure for search engines
Need a Professional Website?
We design and build professional websites with optimized navigation and information architecture. Contact us to get started.