Build a Modern Contact Us Page with Next.js + Tailwind CSS (Component-Based + SEO-Ready)


A well-structured contact page is a must-have for any website. In this tutorial we’ll:

  1. Create reusable React components (ContactForm, ContactInfo, SocialLinks, MapEmbed).
  2. Compose the page in the Next.js App Router (or Pages Router).
  3. Add full SEO – title, meta description, Open Graph, Twitter cards, canonical URL, and optional JSON-LD.
app/
contact/
page.tsx          ← main page (App Router)
components/
ContactForm.tsx
ContactInfo.tsx
SocialLinks.tsx
MapEmbed.tsx
public/
og-contact.jpg      ← 1200×630 Open Graph image
Enter fullscreen mode

Exit fullscreen mode

1. Install Dependencies

npm install lucide-react
# for Pages Router SEO
npm install next-seo
Enter fullscreen mode

Exit fullscreen mode

2. Reusable Components
components/ContactForm.tsx

'use client';

import { useState } from 'react';

export default function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    subject: '',
    message: '',
  });

  const [status, setStatus] = useState<'idle' | 'sending' | 'success' | 'error'>('idle');

  const handleChange = (
    e: React.ChangeEvent
  ) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setStatus('sending');

    // Replace with real API (Formspree, EmailJS, etc.)
    setTimeout(() => {
      setStatus('success');
      setFormData({ name: '', email: '', subject: '', message: '' });
      setTimeout(() => setStatus('idle'), 3000);
    }, 1000);
  };

  return (
    
  );
}
Enter fullscreen mode

Exit fullscreen mode

components/ContactInfo.tsx

import { Mail, Phone, MapPin } from 'lucide-react';

export default function ContactInfo() {
  return (
    

Get in Touch

We'd love to hear from you. Send us a message and we'll respond as soon as possible.

Address

123 Business St, Suite 100
New York, NY 10001

); }
Enter fullscreen mode

Exit fullscreen mode

components/SocialLinks.tsx

import { Facebook, Twitter, Linkedin, Instagram } from 'lucide-react';

export default function SocialLinks() {
  const socials = [
    { Icon: Facebook, label: 'Facebook', href: '#' },
    { Icon: Twitter, label: 'Twitter', href: '#' },
    { Icon: Linkedin, label: 'LinkedIn', href: '#' },
    { Icon: Instagram, label: 'Instagram', href: '#' },
  ];

  return (
    
{socials.map(({ Icon, label, href }) => ( ))}
); }
Enter fullscreen mode

Exit fullscreen mode

components/MapEmbed.tsx

export default function MapEmbed() {
  return (
    

); }
Enter fullscreen mode

Exit fullscreen mode

Tip: Generate the embed URL from Google Maps → Share → Embed a map.

3. The Contact Page (App Router)
app/contact/page.tsx

import ContactForm from '@/components/ContactForm';
import ContactInfo from '@/components/ContactInfo';
import SocialLinks from '@/components/SocialLinks';
import MapEmbed from '@/components/MapEmbed';

// ──────── SEO METADATA ────────
export const metadata = {
  title: 'Contact Us | Your Company Name',
  description:
    'Get in touch with us! Send a message, call, or visit our office. We respond within 24 hours.',
  keywords:
    'contact, support, reach out, customer service, Your Company Name',
  openGraph: {
    title: 'Contact Us | Your Company Name',
    description:
      'We’d love to hear from you. Send us a message and we’ll respond as soon as possible.',
    url: 'https://www.yourwebsite.com/contact',
    siteName: 'Your Company Name',
    images: [
      {
        url: 'https://www.yourwebsite.com/og-contact.jpg',
        width: 1200,
        height: 630,
        alt: 'Contact Us – Your Company Name',
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
  twitter: {
    card: 'summary_large_image',
    title: 'Contact Us | Your Company Name',
    description: 'Get in touch with us anytime!',
    images: ['https://www.yourwebsite.com/og-contact.jpg'],
  },
  robots: { index: true, follow: true },
  alternates: { canonical: 'https://www.yourwebsite.com/contact' },
};

export default function ContactPage() {
  return (
    
{/* Hero */}

Have a question or want to work together? Fill out the form below and we'll get back to you.

{/* Layout */}
{/* Left column */} {/* Right column – Form */}
{/* Optional Map */} {/* ──────── OPTIONAL JSON-LD ──────── */}