A well-structured contact page is a must-have for any website. In this tutorial we’ll:
-
Create reusable React components (
ContactForm,ContactInfo,SocialLinks,MapEmbed). - Compose the page in the Next.js App Router (or Pages Router).
- 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
1. Install Dependencies
npm install lucide-react
# for Pages Router SEO
npm install next-seo
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 (
);
}
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
);
}
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 (
);
}
components/MapEmbed.tsx
export default function MapEmbed() {
return (
);
}
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 ──────── */}
);
}
4. Pages-Router Alternative (if you’re not on App Router)
// pages/contact.tsx
import Head from 'next/head';
import { NextSeo } from 'next-seo';
import ContactForm from '@/components/ContactForm';
import ContactInfo from '@/components/ContactInfo';
import SocialLinks from '@/components/SocialLinks';
import MapEmbed from '@/components/MapEmbed';
export default function ContactPage() {
const SEO = { /* same object as metadata above */ };
return (
<>
{/* ...same JSX as inside the App Router page... */}
>
);
}
5. Open Graph Image
Create public/og-contact.jpg
Dimensions: 1200 × 630 px
Content: “Contact Us” + logo + subtle background
Tools: Canva, Figma, or Photoshop
That’s it! You now have a clean, component-based, fully SEO-optimized Contact Us page ready for production.
