Contact
The Contact component (GetContact) provides a fully functional contact form with email integration via EmailJS and spam protection using Google reCAPTCHA. It features a modern design with SpotlightCard effects and toast notifications.
Overview
This component creates an engaging contact section with a form that sends emails directly to your inbox without requiring a backend server. It includes client-side validation, reCAPTCHA verification, and user feedback via toast notifications.
Dependencies
npm install @emailjs/browser react-google-recaptcha
import { useRef , useState } from 'react' ;
import emailjs from '@emailjs/browser' ;
import SpotlightCard from '../SpotlightCard/SpotLightCard' ;
import ReCAPTCHA from 'react-google-recaptcha' ;
Props
The GetContact component does not accept props. Configuration is done through EmailJS service and reCAPTCHA setup.
Usage
Basic Implementation
With Full Page Layout
import GetContact from './components/Getcontact/Getcontact' ;
function App () {
return (
< main >
< section id = "contact" >
< GetContact />
</ section >
</ main >
);
}
Setup Requirements
1. EmailJS Configuration
You need to create an EmailJS account and configure a service and template:
Sign up at EmailJS
Create an email service (Gmail, Outlook, etc.)
Create an email template
Get your Service ID, Template ID, and Public Key
In the component, update these values:
emailjs . sendForm (
'service_dl7ji3p' , // Your Service ID
'template_pfbhj3g' , // Your Template ID
form . current ,
'BbaI-yQrHrGFriM_6' // Your Public Key
)
2. reCAPTCHA Configuration
Get a reCAPTCHA site key from Google reCAPTCHA
Add to your environment variables:
# .env
VITE_SITE_KEY = your_recaptcha_site_key_here
Never commit your reCAPTCHA site key or EmailJS credentials to public repositories. Use environment variables.
Features
The form includes three fields:
{ /* Name field */ }
< input
type = "text"
name = "name"
required
placeholder = "Your name"
/>
{ /* Email field */ }
< input
type = "email"
name = "email"
required
placeholder = "Your email"
/>
{ /* Message field */ }
< textarea
name = "message"
rows = "5"
required
placeholder = "Write your message here..."
/>
2. reCAPTCHA Integration
const [ captchaVerified , setCaptchaVerified ] = useState ( false );
< ReCAPTCHA
ref = { recaptchaRef }
sitekey = { import . meta . env . VITE_SITE_KEY }
onChange = { () => setCaptchaVerified ( true ) }
onExpired = { () => setCaptchaVerified ( false ) }
theme = "dark"
/>
Prevents form submission without verification:
if ( ! captchaVerified ) {
showToast ( "Please complete the reCAPTCHA." , "error" );
return ;
}
3. Toast Notifications
Provides user feedback for:
Successful submission
Errors
Missing reCAPTCHA verification
const [ toast , setToast ] = useState ( null );
const showToast = ( msg , type = "success" ) => {
setToast ({ msg , type });
setTimeout (() => setToast ( null ), 3500 );
};
Automatically resets form and reCAPTCHA after successful submission:
. then (() => {
showToast ( "Message sent successfully!" );
form . current . reset ();
recaptchaRef . current . reset ();
setCaptchaVerified ( false );
})
Component Structure
function GetContact () {
const form = useRef ();
const recaptchaRef = useRef ();
const [ toast , setToast ] = useState ( null );
const [ captchaVerified , setCaptchaVerified ] = useState ( false );
const sendEmail = ( e ) => {
e . preventDefault ();
if ( ! captchaVerified ) {
showToast ( "Please complete the reCAPTCHA." , "error" );
return ;
}
emailjs . sendForm ( /* ... */ )
. then (() => {
showToast ( "Message sent successfully!" );
// Reset form
})
. catch (() => {
showToast ( "Something went wrong. Try again." , "error" )
});
};
return (
< section >
{ /* Content section */ }
{ /* Form in SpotlightCard */ }
{ /* Toast notification */ }
</ section >
);
}
Customization
Personalizing Text Content
< div className = "w-full md:flex-1 text-center md:text-left md:mr-24" >
< p className = "text-sm tracking-widest uppercase text-white/50 mb-2" >
[YOUR LABEL]
</ p >
< h2 className = "text-3xl font-bold text-white mb-4" >
[Your Heading]
</ h2 >
< hr className = "border-2 border-[#3A3C41] mb-4 w-3/4 mx-auto md:mx-0" />
< p className = "text-[#C7C7C7] text-lg leading-relaxed" >
[Your description]
</ p >
</ div >
< form ref = { form } onSubmit = { sendEmail } >
{ /* Existing fields... */ }
{ /* NEW: Phone field */ }
< div className = "flex flex-col mb-6" >
< label className = "font-semibold text-white mb-2" > Phone </ label >
< input
type = "tel"
name = "phone"
placeholder = "Your phone number"
className = "px-4 py-3 border border-[#3A3C41] rounded-xl bg-[#1E1F22] text-white outline-none focus:border-[#4C8CF5] transition-colors duration-200"
/>
</ div >
{ /* NEW: Subject field */ }
< div className = "flex flex-col mb-6" >
< label className = "font-semibold text-white mb-2" > Subject </ label >
< input
type = "text"
name = "subject"
required
placeholder = "Message subject"
className = "px-4 py-3 border border-[#3A3C41] rounded-xl bg-[#1E1F22] text-white outline-none focus:border-[#4C8CF5] transition-colors duration-200"
/>
</ div >
</ form >
When adding new fields, update your EmailJS template to include the new field names.
Custom Toast Styling
{ /* Success toast - Green */ }
{ toast && toast . type === 'success' && (
< div className = "fixed top-5 right-5 px-5 py-3 rounded-xl text-white text-sm z-50 shadow-lg bg-green-500" >
{ toast . msg }
</ div >
)}
{ /* Error toast - Red */ }
{ toast && toast . type === 'error' && (
< div className = "fixed top-5 right-5 px-5 py-3 rounded-xl text-white text-sm z-50 shadow-lg bg-red-500" >
{ toast . msg }
</ div >
)}
{ /* Two-column layout for name and email */ }
< div className = "flex gap-4 mb-6" >
< div className = "flex flex-col flex-1" >
< label className = "font-semibold text-white mb-2" > Name </ label >
< input type = "text" name = "name" required />
</ div >
< div className = "flex flex-col flex-1" >
< label className = "font-semibold text-white mb-2" > Email </ label >
< input type = "email" name = "email" required />
</ div >
</ div >
EmailJS Template Setup
Create a template in EmailJS with these variables:
<!-- Email template example -->
< h2 > New Contact Form Submission </ h2 >
< p >< strong > Name: </ strong > {{name}} </ p >
< p >< strong > Email: </ strong > {{email}} </ p >
< p >< strong > Message: </ strong ></ p >
< p > {{message}} </ p >
The name attributes in your form inputs must match the template variables:
< input name = "name" /> { /* matches {{name}} */ }
< input name = "email" /> { /* matches {{email}} */ }
< textarea name = "message" /> { /* matches {{message}} */ }
Styling Details
className = "px-4 py-3 border border-[#3A3C41] rounded-xl bg-[#1E1F22] text-white outline-none focus:border-[#4C8CF5] transition-colors duration-200"
Dark background (#1E1F22)
Gray border (#3A3C41)
Blue focus border (#4C8CF5)
Rounded corners (12px)
Smooth color transitions
className = "w-full bg-white/10 backdrop-blur-md text-white px-5 py-3 rounded-xl text-sm font-medium border border-white/20 hover:bg-white/20 hover:-translate-y-0.5 active:translate-y-0 transition-all duration-200 shadow-lg"
Full width
Glassmorphic effect
Hover lift animation
Active press animation
Spotlight Card
spotlightColor = "rgba(0, 229, 255, 0.2)"
className = "w-full max-w-[450px] rounded-2xl"
Cyan spotlight effect
Max width 450px
Rounded corners
Responsive Design
Layout
Mobile (< 768px):
Single column layout
Centered alignment
Smaller padding
Desktop (≥ 768px):
Two-column layout (text + form)
Left-aligned text
Larger padding (p-8)
className = "w-full max-w-[450px]"
Form has:
Full width on mobile
Max 450px width on larger screens
Centered in container
Error Handling
emailjs . sendForm ( /* ... */ )
. then (() => {
showToast ( "Message sent successfully!" );
form . current . reset ();
recaptchaRef . current . reset ();
setCaptchaVerified ( false );
})
. catch (( error ) => {
console . error ( 'EmailJS Error:' , error );
showToast ( "Something went wrong. Try again." , "error" );
});
Accessibility
Semantic HTML form elements
Proper label associations
Required field validation
Focus states on inputs
ARIA-friendly reCAPTCHA
Error messages via toast
Keyboard accessible
Security Best Practices
Follow these security best practices:
Environment Variables : Store sensitive keys in .env file
reCAPTCHA : Always validate reCAPTCHA before submission
Email Validation : Use type="email" for email fields
Rate Limiting : EmailJS provides automatic rate limiting
Domain Restrictions : Configure allowed domains in EmailJS dashboard
Common Issues & Solutions
EmailJS Not Working
// Make sure form fields have name attributes
< input name = "name" /> // ✓ Correct
< input /> // ✗ Wrong
// Verify EmailJS credentials are correct
emailjs . sendForm (
'YOUR_SERVICE_ID' , // Check this
'YOUR_TEMPLATE_ID' , // Check this
form . current ,
'YOUR_PUBLIC_KEY' // Check this
)
reCAPTCHA Not Showing
// Ensure site key is loaded from environment
const siteKey = import . meta . env . VITE_SITE_KEY ; // Vite
const siteKey = process . env . REACT_APP_SITE_KEY ; // Create React App
< ReCAPTCHA
sitekey = { siteKey }
// ...
/>
Toast Not Disappearing
// Ensure timeout is properly set
const showToast = ( msg , type = "success" ) => {
setToast ({ msg , type });
setTimeout (() => setToast ( null ), 3500 ); // 3.5 seconds
};
Testing
Test form submission with valid data
Test validation by submitting empty fields
Test reCAPTCHA by submitting without verification
Test error handling by using invalid EmailJS credentials
Test responsiveness on different screen sizes
Check email delivery in your inbox
EmailJS has a free tier limit of 200 emails per month. Monitor your usage in the EmailJS dashboard.