How to Create a Contact Form with JavaScript
Last updated: March 2026
A standard HTML form refreshes the page on submit. With JavaScript, you can submit forms asynchronously, show inline success or error messages, and create a smoother user experience. This guide shows how to build a JavaScript-powered contact form that sends data to a form backend. No server code required.
You'll go from a basic HTML form to a fully functional JavaScript contact form with validation, error handling, and a polished UX, all in vanilla JS.
Basic HTML form vs JavaScript form
Before adding JavaScript, it helps to understand what changes and what stays the same.
A basic HTML form submits data via the browser's built-in behavior. When a user clicks submit, the browser sends a POST request to the URL in the form's action attribute, then navigates to the server's response. This causes a full page reload or redirect.
A JavaScript form intercepts the submit event, sends the data in the background using fetch(), and updates the page without a reload. The user stays on the same page and sees inline feedback, like a success message or an error.
| Basic HTML form | JavaScript form | |
|---|---|---|
| How it submits | Browser sends POST, navigates to response | fetch() sends POST in background |
| Page reload | Yes - full reload or redirect | No - stays on the same page |
| User feedback | New page or redirect | Inline success/error messages |
| Submit button state | No control | Can show loading state, disable button |
| Error handling | Server-rendered error page | Inline error message, user can retry |
| Data sent | Same form data | Same form data |
Both approaches send the exact same data to the server. JavaScript just gives you control over the experience around the submission.
Build a JavaScript contact form
Follow these four steps to create a working contact form with JavaScript and FormWit as the form backend. No server-side code required.
Step 1: Create a FormWit account and get your endpoint
Go to app.formwit.com/auth/signup and create a free account. No credit card required.
In your dashboard, click Create Form and give it a name (e.g., "Contact Form"). You'll get a unique endpoint URL that looks like this:
https://app.formwit.com/api/s/YOUR_FORM_ID This is the URL your JavaScript will send form data to.
Step 2: Create the HTML form
Add this HTML to your page. It includes a form with name, email, and message fields, a honeypot field for spam protection, and a status message element that JavaScript will use to show feedback.
<form id="contact-form" action="https://app.formwit.com/api/s/YOUR_FORM_ID" method="POST">
<label for="name">Name</label>
<input type="text" id="name" name="name" required />
<label for="email">Email</label>
<input type="email" id="email" name="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" required></textarea>
<!-- Honeypot spam protection -->
<input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />
<button type="submit">Send Message</button>
<p id="form-status" style="display:none"></p>
</form> Key details: The id="contact-form" lets JavaScript find the form. The action attribute holds your FormWit endpoint URL. The hidden _gotcha field is a honeypot. Bots fill it in, humans don't. The #form-status paragraph is hidden by default and will be shown by JavaScript after submission.
Step 3: Add the JavaScript
Add this script after the form (or in a separate .js file). It intercepts the form's submit event, sends the data with fetch(), and shows a success or error message.
const form = document.getElementById('contact-form');
const status = document.getElementById('form-status');
const button = form.querySelector('button[type="submit"]');
form.addEventListener('submit', async (e) => {
e.preventDefault();
button.disabled = true;
button.textContent = 'Sending...';
status.style.display = 'none';
try {
const response = await fetch(form.action, {
method: 'POST',
body: new FormData(form),
});
if (response.ok) {
status.textContent = 'Message sent successfully!';
status.style.color = '#16a34a';
form.reset();
} else {
throw new Error('Server error');
}
} catch (error) {
status.textContent = 'Something went wrong. Please try again.';
status.style.color = '#dc2626';
}
status.style.display = 'block';
button.disabled = false;
button.textContent = 'Send Message';
}); Here's what the code does:
e.preventDefault()stops the browser's default form submission (no page reload).new FormData(form)automatically collects all form field values, including the honeypot.fetch(form.action, ...)sends the data to your FormWit endpoint in the background.button.disabled = trueprevents double-clicks while the request is in progress.- On success, the form resets and shows a green confirmation. On failure, a red error message appears.
Step 4: Test it
Open your page in a browser and submit the form. You should see the button text change to "Sending...", then a green "Message sent successfully!" message appear below the button. Check your FormWit dashboard. The submission will be there, and you'll receive an email notification.
If something goes wrong (network error, invalid endpoint), the red error message will appear instead, and the user can try again without losing their input.
Adding form validation
HTML5 validation attributes like required and type="email" handle the basics. But you can add custom JavaScript validation for more control, like checking message length or running a regex on the email field.
Add this validation function and call it at the start of your submit handler:
function validateForm(form) {
const name = form.querySelector('#name').value.trim();
const email = form.querySelector('#email').value.trim();
const message = form.querySelector('#message').value.trim();
if (name.length < 2) {
return 'Please enter your full name.';
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return 'Please enter a valid email address.';
}
if (message.length < 10) {
return 'Message must be at least 10 characters.';
}
return null;
}
// Inside your submit handler, before the fetch call:
form.addEventListener('submit', async (e) => {
e.preventDefault();
const validationError = validateForm(form);
if (validationError) {
status.textContent = validationError;
status.style.color = '#dc2626';
status.style.display = 'block';
return;
}
// ... rest of the fetch logic
}); This runs before any network request is made. If validation fails, the user sees the error immediately without waiting for a server response.
Custom redirect after submission
There are two ways to redirect users after a successful submission.
Option 1: Hidden field (server-side redirect)
Add a hidden redirect_to field to your form. If you're submitting the form without JavaScript (as a fallback), FormWit will redirect the user to this URL after processing:
<input type="hidden" name="redirect_to" value="https://yoursite.com/thank-you" /> Option 2: JavaScript redirect
When submitting via JavaScript, you control the response. Replace the success message with a redirect:
if (response.ok) {
window.location.href = 'https://yoursite.com/thank-you';
} else {
throw new Error('Server error');
} The JavaScript approach gives you more flexibility. You can add a delay, show a brief success message before redirecting, or conditionally redirect based on form values.
Works with any framework
This vanilla JavaScript approach works everywhere. There's no dependency on a specific framework or build tool. You can use this code in:
- Plain HTML sites - just add the form and script tag.
- WordPress themes - add the HTML to a page template or widget, and the JavaScript to your theme's footer or a custom script block.
- Squarespace, Wix, or Carrd - use the platform's code injection or embed block to add the form and script.
- Static site generators (Astro, Hugo, Jekyll, Eleventy) - include the form in any template or page.
- JavaScript frameworks (React, Vue, Svelte) - use this vanilla JS as a starting point, then adapt it to the framework's event handling and state management patterns.
The form backend doesn't care how your frontend is built. It receives a standard POST request with form data and processes it the same way regardless of the source.
Summary
A JavaScript contact form gives you full control over the submission experience: no page reloads, inline feedback, loading states, and client-side validation. Combined with a form backend like FormWit, you get all of this without writing any server-side code.
FormWit's free plan includes unlimited forms, 100 submissions per month, email notifications, and built-in spam protection. Get started free.
Related guides: HTML contact form · React contact form · Form to email · Spam protection · Contact form templates
Frequently asked questions
Can I submit forms without page reload?
Yes. Use e.preventDefault() in the submit handler and send the data with fetch(). The form data is sent in the background, and you update the page with a success or error message using DOM manipulation. The user stays on the same page the entire time.
What API does FormWit use?
FormWit accepts standard HTTP POST requests with FormData or URL-encoded body. Your endpoint URL is https://app.formwit.com/api/s/YOUR_FORM_ID. Send a POST with your form fields as the body and FormWit returns a 200 on success. No API keys or authentication headers needed for submissions.
How do I handle errors?
Wrap your fetch call in a try/catch block. Check response.ok for server errors (4xx/5xx status codes) and catch network failures in the catch block. Show an inline error message so the user can retry without losing their input.
Want to skip the setup?
FormWit gives you a form endpoint in 60 seconds. Free plan, no credit card.
Need a form fast?
Build one visually with our free HTML form generator — no coding required.
Try the Form Generator →Submit your first form with JavaScript
Add a contact form to your site in 30 seconds. No backend code required.
Try FormWit Free