The Contact Form provides visitors with an easy way to reach out for project inquiries, collaborations, or general questions. It features email integration, real-time validation, and automated responses.
Overview
Located in src/components/ContactSection.tsx, this component offers:
Professional contact form with validation
Email API integration for message delivery
Real-time status feedback (success/error messages)
Auto-reply system for sender confirmation
Direct email fallback for redundancy
Responsive design with attractive layout
User Experience Flow
Sending a Message
Fill Form : User enters name, email, subject, and message
Submit : Click “Enviar Mensagem” button
Loading State : Button shows spinner and “Enviando…” text
Confirmation : Success message appears, form resets
Auto-Reply : User receives confirmation email automatically
Form Fields
Name : Full name of the sender
Email : Reply-to email address
Subject : Brief topic description
Message : Detailed message (multi-line)
State Management
const [ formData , setFormData ] = useState ({
name: "" ,
email: "" ,
subject: "" ,
message: "" ,
});
const [ isSubmitting , setIsSubmitting ] = useState ( false );
const [ submitStatus , setSubmitStatus ] = useState < 'idle' | 'success' | 'error' >( 'idle' );
< form onSubmit = { handleSubmit } className = "space-y-4" >
{ /* Name field */ }
< div >
< label htmlFor = "name" className = "block text-sm font-medium mb-2" >
Nome
</ label >
< input
type = "text"
id = "name"
name = "name"
value = { formData . name }
onChange = { handleChange }
required
className = "w-full px-4 py-3 rounded-xl bg-secondary border border-border"
placeholder = "Seu nome"
/>
</ div >
{ /* Email, Subject, Message fields... */ }
< Button type = "submit" disabled = { isSubmitting } >
{ isSubmitting ? (
<>< Loader2 className = "animate-spin" /> Enviando... </>
) : (
<>< Send /> Enviar Mensagem </>
) }
</ Button >
</ form >
API Integration
The form submits to the backend contact endpoint:
const handleSubmit = async ( e : React . FormEvent ) => {
e . preventDefault ();
setIsSubmitting ( true );
setSubmitStatus ( 'idle' );
try {
const response = await fetch ( '/api/contact' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
name: formData . name ,
email: formData . email ,
subject: formData . subject ,
message: formData . message ,
}),
});
if ( response . ok ) {
setSubmitStatus ( 'success' );
setFormData ({ name: "" , email: "" , subject: "" , message: "" });
setTimeout (() => setSubmitStatus ( 'idle' ), 5000 );
} else {
throw new Error ( 'Erro ao enviar mensagem' );
}
} catch ( error ) {
console . error ( 'Erro ao enviar email:' , error );
setSubmitStatus ( 'error' );
setTimeout (() => setSubmitStatus ( 'idle' ), 5000 );
} finally {
setIsSubmitting ( false );
}
};
Status messages automatically disappear after 5 seconds to keep the UI clean and prevent confusion.
Status Feedback
Success Message
{ submitStatus === 'success' && (
< div className = "flex items-center gap-2 p-4 rounded-xl bg-green-500/10 border border-green-500/20 text-green-500" >
< CheckCircle className = "w-5 h-5" />
< span > Mensagem enviada com sucesso! Responderei em breve. </ span >
</ div >
)}
Error Message
{ submitStatus === 'error' && (
< div className = "flex items-center gap-2 p-4 rounded-xl bg-red-500/10 border border-red-500/20 text-red-500" >
< XCircle className = "w-5 h-5" />
< span > Erro ao enviar mensagem. Tente novamente ou use o email direto. </ span >
</ div >
)}
Below the form, a direct email option is provided:
< div className = "p-6 rounded-xl bg-secondary border border-border" >
< div className = "flex items-center gap-3 text-muted-foreground" >
< Mail className = "w-5 h-5 text-primary" />
< div >
< p className = "text-sm" > Email direto </ p >
< a
href = "mailto:[email protected] "
className = "text-foreground hover:text-primary transition-colors"
>
[email protected]
</ a >
</ div >
</ div >
</ div >
The direct email option ensures users can always contact you, even if the API is temporarily unavailable.
Two-Column Layout
The section uses a responsive grid layout:
< div className = "grid lg:grid-cols-2 gap-12 items-start max-w-5xl mx-auto" >
{ /* Left: Contact Form */ }
< ScrollReveal variant = "fade-right" delay = { 100 } >
< div className = "space-y-6" >
{ /* Form content */ }
</ div >
</ ScrollReveal >
{ /* Right: Decorative Image */ }
< ScrollReveal variant = "fade-left" delay = { 300 } >
< div className = "relative flex justify-center lg:justify-end" >
< div className = "relative bg-card rounded-3xl p-8 border border-border" >
< img
src = { memojiThinking }
alt = "Contato"
className = "w-64 h-64 md:w-80 md:h-80 object-contain mx-auto animate-float"
/>
</ div >
</ div >
</ ScrollReveal >
</ div >
Visual Effects
The decorative image includes:
Glow effect : Gradient blur background
Float animation : Gentle up-down motion
Card container : Bordered rounded card
Scroll animation : Slides in from left with delay
< div className = "text-center mb-16" >
< span className = "section-title" > Contato </ span >
< h2 className = "heading-md" >
Vamos trabalhar < span className = "text-gradient" > juntos? </ span >
</ h2 >
< p className = "text-muted-foreground mt-4 max-w-2xl mx-auto" >
Estou disponível para projetos freelance de desenvolvimento web,
análise de dados e automação. Entre em contato e vamos transformar
suas ideias em realidade!
</ p >
</ div >
Client-Side Validation
HTML5 validation is used for basic checks:
Server-Side Validation
The backend API validates:
Email format (proper structure)
Required fields (none empty)
Message length (reasonable limits)
Spam detection (rate limiting)
Email System
When a message is submitted, two emails are sent:
1. Notification Email (to you)
To: [email protected]
Subject: [Portfolio] New Contact: {subject}
Name: {name}
Email: {email}
Subject: {subject}
Message:
{message}
2. Confirmation Email (to sender)
To: {email}
Subject: Mensagem recebida - André Ruperto
Olá {name},
Recebi sua mensagem sobre "{subject}" e responderei em breve.
Obrigado pelo contato!
André Ruperto
Email Templates Custom HTML email templates are used for professional appearance. Preview them in the Admin Panel .
Responsive Design
Mobile (< 1024px)
Stacked layout (form then image)
Full-width form fields
Smaller decorative image
Maintained padding
Desktop (≥ 1024px)
Two-column grid
Form on left, image on right
Larger decorative image
Generous spacing
Accessibility Features
Semantic HTML : Proper label-input associations
ARIA labels : Clear button descriptions
Keyboard navigation : Full tab support
Focus indicators : Visible focus states
Error messages : Descriptive feedback
Loading states : Disabled state during submission
< label htmlFor = "email" className = "block text-sm font-medium mb-2" >
Email
</ label >
< input
type = "email"
id = "email"
name = "email"
aria-required = "true"
aria-invalid = { submitStatus === 'error' }
/>
Integration with Backend
The contact form relies on the Express backend:
// Backend endpoint: POST /api/contact
// Expected body: { name, email, subject, message }
// Response: { success: boolean }
For backend implementation details, see:
Before deploying, test the contact form thoroughly:
Submit valid message - should succeed
Submit with invalid email - should show validation error
Submit with empty fields - should show required field errors
Test direct email link - should open email client
Verify both notification and confirmation emails are received
Common Issues
Check API endpoint is accessible
Verify CORS settings in backend
Check browser console for errors
Emails Not Sending
Verify SMTP credentials in .env
Check email service configuration
Review server logs for errors
Validation Errors
Ensure all required fields are filled
Check email format is valid
Verify backend validation rules
For troubleshooting, see Common Issues .