📌 Introduction:
Want to build a full contact form that actually works?
In this tutorial, I’ll show you how to build a fully functional Contact Form using React for the frontend, Node.js + Express for the backend, and MongoDB to store the data.
Plus, we’ll send email notifications every time someone submits the form!

This is perfect if you're:

Learning how the frontend talks to the backend

Building your portfolio

Wanting to offer real-time feedback to users

Let’s dive in! 🛠️

🧱 Project Structure
contact-form/
├── client/ # React frontend
└── server/ # Node.js + Express backend

npx create-react-app client
cd client
npm install axios

📄 Create a Simple Contact Form
client/src/ContactForm.js
import React, { useState } from 'react';
import axios from 'axios';

const ContactForm = () => {
const [form, setForm] = useState({ name: '', email: '', message: '' });
const [status, setStatus] = useState('');

const handleChange = e => {
setForm({ ...form, [e.target.name]: e.target.value });
};

const handleSubmit = async e => {
e.preventDefault();
try {
await axios.post('http://localhost:5000/api/contact', form);
setStatus('Message sent successfully!');
setForm({ name: '', email: '', message: '' });
} catch (err) {
setStatus('Failed to send message. Please try again.');
}
};

return (






{status}




export default ContactForm;

🔹 Step 2: Backend with Node.js & Express
✅ Setup
mkdir server
cd server
npm init -y
npm install express mongoose nodemailer cors dotenv

📄 Create Backend Files
server/index.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();

const contactRoutes = require('./routes/contact');

const app = express();
app.use(cors());
app.use(express.json());

app.use('/api/contact', contactRoutes);

mongoose.connect(process.env.MONGO_URI)
.then(() => app.listen(5000, () => console.log('Server running on port 5000')))
.catch(err => console.log(err));

📄 Create Contact Route
server/routes/contact.js
const express = require('express');
const router = express.Router();
const Contact = require('../models/Contact');
const nodemailer = require('nodemailer');

router.post('/', async (req, res) => {
const { name, email, message } = req.body;

try {
const contact = new Contact({ name, email, message });
await contact.save();

// Email Notification
const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS
  }
});

const mailOptions = {
  from: email,
  to: process.env.EMAIL_USER,
  subject: 'New Contact Form Message',
  text: `From: ${name}\nEmail: ${email}\nMessage: ${message}`
};

await transporter.sendMail(mailOptions);

res.status(200).json({ msg: 'Message sent' });

} catch (err) {
res.status(500).json({ msg: 'Error sending message' });
}
});

module.exports = router;

📄 MongoDB Schema
server/models/Contact.js
const mongoose = require('mongoose');

const contactSchema = new mongoose.Schema({
name: String,
email: String,
message: String,
createdAt: {
type: Date,
default: Date.now
}
});

module.exports = mongoose.model('Contact', contactSchema);

🌐 .env File
server/.env
MONGO_URI=your_mongodb_connection_string
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_email_password

💡 Tip: Use environment variables securely. Don't commit .env to GitHub!

✅ Final Step: Test It!
Run the server:
node index.js

Run the React app:
npm start

Visit http://localhost:3000 and try sending a message!

🧠 Common Mistakes
Forgot to enable CORS in backend.

Backend isn’t running or connected to MongoDB.

Gmail blocks Nodemailer – use app password or switch to another SMTP.

🏁 Conclusion
Now you have a full-stack contact form that:

Takes input from users

Sends data to the backend

Saves the message in MongoDB

Sends you an email instantly 🚀