Hello, I’ve got a single contact form that I’ve built into my NextJs site hosted on Netlify and I’m not seeing any successful form submissions in the Netlify Dashboard https://app.netlify.com/sites/YOURSITENAME/forms despite getting successful submissions several times that I’ve tested. When I visit my projects forms dashboard, it detected my contact form which is good, but there is no history of any submissions.
Site name: https://blackstonewebdesigns.com, blackstone-web-designs.netlify.app
Contact form: https://blackstonewebdesigns.com/contact
I’ve looked over the Quote from “[Support Guide] Form problems, form debugging, 404 when submitting - Support / Support Guides - Netlify Support Forums” (support guide) and didn’t see anything that would help with the exception that it’s possible my form submission is being eaten by a redirect. When I submit the form it sends the following payload containing all the appropriate fields to the www.blackstonewebdesigns.com/__forms.html which in the network tab the HTTP status code of the response for me is 303. In the support guide there is one small mention of a redirect that could cause an issue, but I’m not fully certain if that’s actually my issue because they talk about submitting to / and I believe that’s only applicable to static sites.
This is the payload I see in the network tab when I submit my form:
form-name contact
name Test User
email testuser@mailinator.com
phone 5555555555
message This is a test message!
__forms.html is a simple HTML file I’ve put into my /public folder for NextJs and looks as follows:
<html>
<body>
<form
name="contact"
data-netlify="true"
data-netlify-recaptcha="true"
hidden
>
<input type="hidden" name="form-name" value="contact" />
<input name="name" type="text" />
<input name="email" type="email" />
<input name="phone" type="tel" />
<textarea name="message"></textarea>
<div data-netlify-recaptcha="true"></div>
</form>
</body>
</html>
My contact page isn’t being SSR rendered (see the ‘use client’ at the top), but because I’m using React, I’ve followed some guides on the Netlify site it feels like I’m doing everything correct. Here is my contactPage.tsx code:
'use client';
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Mail, Phone } from 'lucide-react';
import { Button } from '@/ui-kit/components/button/button';
import { Card } from '@/ui-kit/components/card/card';
import { CONTACT_EMAIL, CONTACT_PHONE } from '@/constants/info';
import styles from './contactPage.module.css';
const contactFormSchema = z.object({
name: z
.string()
.refine((val) => val.length > 0, { message: 'Please enter a name' })
.min(2, { message: 'Name must be at least 2 characters' }),
email: z.email({ message: 'Please enter a valid email address' }),
phone: z
.string()
.min(10, { message: 'Please enter a valid phone number' })
.regex(/^[\d\s\-\(\)]+$/, {
message:
'Phone number can only contain digits, spaces, dashes, and parentheses',
}),
message: z
.string()
.refine((val) => val.length > 0, { message: 'Please enter a message' })
.min(10, { message: 'Message must be at least 10 characters' })
.max(1000, { message: 'Message must be less than 1000 characters' }),
});
type ContactFormData = z.infer<typeof contactFormSchema>;
export const ContactPage = () => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitStatus, setSubmitStatus] = useState<
'idle' | 'success' | 'error'
>('idle');
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm<ContactFormData>({
resolver: zodResolver(contactFormSchema),
});
const onSubmit = async (data: ContactFormData) => {
setIsSubmitting(true);
setSubmitStatus('idle');
const formData = new URLSearchParams();
formData.append('form-name', 'contact');
formData.append('name', data.name);
formData.append('email', data.email);
formData.append('phone', data.phone);
formData.append('message', data.message);
try {
const response = await fetch('/__forms.html', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
if (response.ok) {
setSubmitStatus('success');
reset();
} else {
setSubmitStatus('error');
}
} catch {
setSubmitStatus('error');
} finally {
setIsSubmitting(false);
}
};
return (
<div className={styles.contactPage}>
<section className={styles.hero}>
<div className={styles.container}>
<h1 className={styles.title}>Get In Touch</h1>
<p className={styles.subtitle}>
Ready to get started? Contact us today to discuss your project.
</p>
</div>
</section>
<section className={styles.content}>
<div className={styles.container}>
<div className={styles.grid}>
<div className={styles.formSection}>
<Card className={styles.formCard}>
<h2 className={styles.sectionTitle}>Send Us a Message</h2>
<p className={styles.description}>
Share your vision for your new website and all the features
you'd like to include. We respond within 24 hours. For
immediate assistance, call us directly—if we're
unavailable, we'll return your call the same day.
</p>
<form
name="contact"
method="POST"
data-netlify="true"
data-netlify-recaptcha="true"
onSubmit={(e) => {
void handleSubmit(onSubmit)(e);
}}
className={styles.form}
>
<input type="hidden" name="form-name" value="contact" />
<div className={styles.formGroup}>
<label htmlFor="name" className={styles.label}>
Name *
</label>
<input
type="text"
id="name"
{...register('name')}
className={styles.input}
aria-invalid={errors.name ? 'true' : 'false'}
/>
{errors.name && (
<span className={styles.errorMessage}>
{errors.name.message}
</span>
)}
</div>
<div className={styles.formGroup}>
<label htmlFor="email" className={styles.label}>
Email *
</label>
<input
type="email"
id="email"
{...register('email')}
className={styles.input}
aria-invalid={errors.email ? 'true' : 'false'}
/>
{errors.email && (
<span className={styles.errorMessage}>
{errors.email.message}
</span>
)}
</div>
<div className={styles.formGroup}>
<label htmlFor="phone" className={styles.label}>
Phone *
</label>
<input
type="tel"
id="phone"
{...register('phone')}
className={styles.input}
aria-invalid={errors.phone ? 'true' : 'false'}
/>
{errors.phone && (
<span className={styles.errorMessage}>
{errors.phone.message}
</span>
)}
</div>
<div className={styles.formGroup}>
<label htmlFor="message" className={styles.label}>
Message *
</label>
<textarea
id="message"
{...register('message')}
rows={6}
className={styles.textarea}
aria-invalid={errors.message ? 'true' : 'false'}
/>
{errors.message && (
<span className={styles.errorMessage}>
{errors.message.message}
</span>
)}
</div>
<div
className={styles.recaptcha}
data-netlify-recaptcha="true"
/>
{submitStatus === 'success' && (
<div className={styles.successMessage}>
Thank you! Your message has been sent successfully.
We'll get back to you soon.
</div>
)}
{submitStatus === 'error' && (
<div className={styles.errorMessage}>
Something went wrong. Please try again or contact us
directly.
</div>
)}
<Button
type="submit"
variant="primary"
size="large"
fullWidth
disabled={isSubmitting}
>
{isSubmitting ? 'Submitting...' : 'Submit'}
</Button>
</form>
</Card>
</div>
<div className={styles.ctaSection}>
<Card className={styles.ctaCard}>
<h2 className={styles.ctaTitle}>Ready to Get Started?</h2>
<p className={styles.ctaDescription}>
Let's discuss your project and how we can help bring your
vision to life.
</p>
<div className={styles.ctaButtons}>
<a href={`tel:${CONTACT_PHONE}`}>
<Button variant="primary" size="large" fullWidth>
<Phone size={20} style={{ marginRight: '0.5rem' }} />
Call Us Now
</Button>
</a>
<a href={`mailto:${CONTACT_EMAIL}`}>
<Button variant="outline" size="large" fullWidth>
<Mail size={20} style={{ marginRight: '0.5rem' }} />
Send Email
</Button>
</a>
</div>
</Card>
</div>
</div>
</div>
</section>
</div>
);
};