When should you reset the form?
After the server has confirmed it received the message. If you clear the fields when the visitor clicks Send and the request then fails, their text is gone and they have to type it again, which most people won't do. So wait for the answer, check it, and only then call form.reset(). On an error, leave everything in place and say what went wrong.
What counts as “success” depends on the service. An HTTP 200 alone proves the request arrived, not that anyone will read it, so check the answer's own field. Formgong answers success: true with the submission's id once it has saved it; the email to you is sent after that, so a slow mail server doesn't keep the visitor waiting.
This only applies when you send with JavaScript. A plain HTML form that posts to its action makes the browser load a new page, the thank-you page, so there is nothing to clear. The code below is the fetch version, with the reset in the right place and the button locked while it sends, so an impatient double click doesn't send the form twice.
<form id="contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="source" value="footer" data-default="footer">
<label>Name <input name="name" required></label>
<label>Email <input type="email" name="email" required></label>
<label>Message <textarea name="message" required></textarea></label>
<button type="submit">Send</button>
<p id="status" role="status"></p>
</form>
<script>
const form = document.getElementById("contact");
const status = document.getElementById("status");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
try {
const response = await fetch(form.action, {
method: "POST", body: new FormData(form), headers: { Accept: "application/json" },
});
const result = await response.json();
if (response.ok && result.success) {
form.reset(); // only after the server said yes
status.textContent = "Thanks, we got your message.";
} else {
status.textContent = result.message || "That didn't go through. Please try again.";
}
} catch {
status.textContent = "Network error. Your text is still in the form.";
} finally {
button.disabled = false;
}
});
// reset() leaves two things behind; clean them up here.
form.addEventListener("reset", () => {
for (const el of form.elements) {
if (el.dataset.default !== undefined) el.value = el.dataset.default; // hidden fields
if (el.setCustomValidity) el.setCustomValidity(""); // custom messages
}
});
</script>What does form.reset() actually restore?
The defaults written in your HTML, which is not the same as empty. On 6 November 2026 we filled a test form in Chromium 153 and reset it:
| Field | Filled with | After reset() |
|---|---|---|
Text input with value="Default name" | Ana Lima | Default name |
| Email input, no value | ana@example.com | (empty) |
| Select, Support pre-selected | Billing | Support |
Checkbox, checked in HTML | Unticked | Ticked |
| Textarea with “Hi,” in it | Need an invoice | Hi, |
| File input | a.txt | (empty) |
Hidden input value="footer", changed by script | pricing-page | pricing-page |
Most rows behave the way you'd hope: the field goes back to what the page loaded with, and the file input empties. The last row is the surprise. A hidden input has no separate “default”, so when a script changes its value, say to record which page the visitor came from, reset() leaves the new value in place. The next submission from that page then carries the old value. The data-default attribute in the code above stores the original so the reset listener can put it back.
What counts as the default can change after the page loads. In a second test, setting input.value from a script did nothing to the default: reset() went back to “Default name”. Calling setAttribute("value", "New default"), or assigning input.defaultValue, did change it, and the next reset restored the new text. Use that when a form should come back prefilled with something you only know after load, such as the visitor's email after they sign in.
If you want a truly empty form, don't prefill it. Placeholders don't count as values, so placeholder="Your name" is fine; value="Your name" comes back after every reset.
What else does reset() leave behind?
We found more than that.
Custom error messages stay. We set setCustomValidity("Taken") on the email field, then reset the form. The field was empty again, but the browser still considered it invalid with the message “Taken”, so the next submission would be blocked for a reason that no longer applies. Clear custom messages in the reset listener.
No input or change events fire. The form fires one reset event and that's it. A character counter, a “3 of 5 fields done” bar or anything else that listens to typing won't notice the fields emptied, so update them from the reset listener.
That event comes before the fields change, not after. Inside our listener the name field still held “Ana”; it only went back to its default once the listener had finished. The event can also be cancelled: with event.preventDefault() in the listener, nothing was reset at all. So a listener that reads the fields sees the old values, and one that writes a field the reset also touches will be overwritten. The listener in our code is safe because the browser leaves hidden fields and custom messages alone; we checked that it puts the hidden default back and clears the message.
Anything that isn't a form field stays as it was. A rich-text box built on contenteditable kept the visitor's text, an aria-invalid="true" you set on a field stayed, and a button disabled by script stayed disabled. Error text you inserted next to fields is ordinary page content, so it stays too. Remove all of that yourself, and use the editor's own clear method if it has one.
One more trap: a field called name="reset". The form exposes its fields as properties, so form.reset then means that field, and calling it failed with “TypeError: f.reset is not a function”. Rename the field. The same happens to form.submit() with a field named submit.
How do you reset a form in React or Vue?
Reset the data, not only the page. In React, a controlled input takes its value from state, and in our test form.reset() did nothing to one: the field still said “Ana”, because React keeps the input's value attribute equal to the state, so the “default” the browser restores is the current text. Set the state back to its starting values instead, for example setValues(initialValues) after a successful send.
Uncontrolled inputs, the ones with defaultValue and no value, are ordinary DOM fields, so a ref to the form and formRef.current.reset() works. In React 19, if you pass a function to the form's action, React resets the uncontrolled fields itself once that function finishes without throwing. Its documentation warns that returning a validation error instead of throwing also counts, so give the fields a defaultValue from state if they must survive an error. With react-hook-form, its docs say not to call reset() inside onSubmit, and to call it in a useEffect that runs when formState.isSubmitSuccessful becomes true.
Vue goes wrong the other way. We bound a field with v-model, typed “Ana” and called form.reset(): the field emptied, but the reactive object still held “Ana”, so code that sends the object would send the old text. Reset the object, for example Object.assign(form, initialValues()), and the field follows.
Why are the fields filled again after pressing Back?
Because the browser remembers what was typed. We posted a form the plain HTML way, got a 303 redirect to a thank-you page, and pressed Back. Chromium brought the name, the email and the message back into the fields, ready to be sent a second time.
Adding autocomplete="off" to the <form> stopped that in our test: after Back, every field showed its default again. A common fix found online, resetting the form in a pageshow listener when event.persisted is true, did nothing here: persisted was false, so the page had not come from the back-forward cache, and Chromium still put the typed values back. If you need the fields empty after Back, autocomplete="off" on the form is the reliable switch, at the cost of the browser's own autofill suggestions in that form.
How Formgong's code resets the form
The snippets in our HTML forms docs and in the form generator do what this article recommends: they send with fetch, read the JSON answer, and call form.reset() only when success is true. If you'd rather not write JavaScript at all, post the form normally: Formgong answers with a 303 redirect to its thank-you page or to your own thank-you page, and the form is left behind.
After a reset, tell people it worked. The status line in our code has role="status", so screen readers read the thanks out without moving focus. If you hide the form and show only the message, also give the message tabindex="-1" and move focus to it, or keyboard users are left on a button that no longer exists.
Once the form is done, the same account can add an AI help chat that answers questions on the page and a reviews widget that shows what earlier customers said.
Did reset() leave something else behind?
If form.reset() missed a field type we did not test, or a framework kept old values after it, tell us at support@formgong.com. We will reproduce it and add it here.
Frequently asked questions
How do I clear a form after submit in JavaScript?
Call form.reset() after your fetch request returns success. On an error, keep the fields so the visitor doesn't lose their text.
Why doesn't form.reset() empty my fields?
reset() restores the values written in the HTML. A field with a value attribute goes back to that value. Use placeholder instead of value for hints.
Does form.reset() clear hidden inputs?
No, not if a script changed them. In our test a hidden field kept its script-set value. Store the default and restore it in a reset listener.
How do I reset a form in React?
Set the state back to its starting values. In our test form.reset() did nothing to a controlled React input. For uncontrolled inputs, call reset() on a ref to the form.
How do I stop the form refilling after the Back button?
Add autocomplete="off" to the form element. In our Chromium test the fields came back empty after Back.
Sources and documentation
Official references for this guide: . HTML forms, where data is stored.
Related guides
- Lovable form submissions to email and Telegram
- HTML contact form without a backend: a working example
- How to send website form submissions to Telegram
- Contact form not sending email? Check where it stops
- Managing website leads in Telegram without a CRM
- Form backend for Lovable, Bolt, v0, Cursor
- Telegram bot for a contact form: build or skip?
- GDPR form backend: 7 checks before you choose
- Lovable form not sending email? 6 fixes
- Netlify Forms not working? React and Bolt fixes
- Stop contact form spam without a CAPTCHA
- GitHub Pages contact form: a working setup
- Mailto Form in HTML: Why It Fails and What to Use
- HTML form to Google Sheets: 2 free methods
- Webflow form submission limit: what to do at 50
- Turnstile vs reCAPTCHA vs hCaptcha for forms
- Contact Form 7 and Elementor forms to Telegram
- Squarespace contact form not sending email?
- Shopify contact form: where do messages go?
- Google Form to Telegram: free Apps Script way
- Wix contact form not sending email? Fixes
- EU / GDPR Formspree alternatives compared
- HTML form action attribute explained
- How do HTML forms work? The HTTP request
- Types of Injection Attacks on Web Forms (2026)
- Indirect Prompt Injection in MCP
- MCP Rug Pull Attack: Detect Tool Changes
- Form without a backend: 7 ways that work
- Thank-you page after form submission (HTML)
- Indirect Prompt Injection Examples (2023–2026)
- Indirect Prompt Injection via Email
- What Is Tool Poisoning in MCP?
- WordPress contact form without a plugin
- Send email from frontend JavaScript
- How to Prevent Indirect Prompt Injection
- Honeypot Form Field: How to Add One That Works
- Contact Form with File Upload (HTML, No PHP)
- Angular contact form without a backend
- Send form submissions to Slack or Discord without Zapier
- Verify a form webhook signature (HMAC-SHA256)
- Contact forms that send nothing: 793 AI-built sites tested
- v0 contact form that actually sends: 3 ways
- How we tested AI-built contact forms, and 12 bugs we hit
- Cloudflare vs Netlify free plan: hosting that never pauses
- EmailJS 412 “Gmail_API: Invalid grant”: reconnect Gmail
- Resend “You can only send testing emails”: verify a domain
- Supabase Edge Function blocked by CORS policy: 3 causes
- Formspree “Form not found” and other errors: fixes
- Web3Forms errors: “Invalid access key” and 403 explained
- How to add customer reviews to your website for free
- Getform not working? “This form has been deleted” and more
- Next.js contact form not working? 6 errors, reproduced
- Webflow form not sending email? What to check, tested
- FormSubmit not working? “This form needs Activation” fix
- Contact form “TypeError: Failed to fetch”: causes and fixes
- WooCommerce product enquiry form
- Contact Form 7 vs WPForms
- Gravity Forms alternative free
- WordPress contact form block
- 535-5.7.8 Username and Password not accepted (Gmail)
- 535 5.7.3 Authentication unsuccessful: Office 365 SMTP
- Nodemailer “Missing credentials for "PLAIN"”: the fix
- Nodemailer “Greeting never received”: port 465 fix
- Nodemailer SSL “wrong version number”: the port fix
- Nodemailer “self-signed certificate in certificate chain”
- Nodemailer ECONNREFUSED 127.0.0.1:587: missing SMTP host
- SendGrid “authorization grant is invalid”: 401 fix
- Mailgun 401 Forbidden: why the API rejects your key
- “Edge Function returned a non-2xx status code”: the fix
- Next.js “Body exceeded 1 MB limit”: Server Action fix
- Unexpected token '<', "<!DOCTYPE "... is not valid JSON
- “TypeError: Body is unusable”: body has already been read
- Turnstile “timeout-or-duplicate” and other siteverify errors
- Turnstile vs hCaptcha vs reCAPTCHA: speed and size tested
- Judge.me reviews not showing on Shopify: how to fix it
- Judge.me review carousel not showing: how to fix it
- Yotpo reviews not showing on Shopify? Check the app embed
- Loox reviews not showing on product page: how to fix
- Shopify reviews not showing: what to check first
- How to show reviews on Shopify
- GDPR for website forms: what each type of form needs
- WooCommerce reviews not showing: how to fix it
- Stamped.io reviews not showing on Shopify: how to fix it
- Etsy reviews not showing: why and what to do
- Trustpilot widget not loading: how to fix TrustBox
- Yotpo problems in 2026: what merchants report
- Contact Form 7 “error trying to send your message” fix
- Elementor form “Your submission failed because of an error”
- Framer form not sending email or not working: what to check
- Carrd contact form not working: plans, spam and errors
- Google review link not working: what customers see and why
- tawk.to widget not showing on your website: causes and fixes
- How to add questions and answers to your product page
- “Failed to send a request to the Edge Function”: fixes
- Next.js “Failed to find Server Action”: what it means
- Brevo “unauthorized: Key not found” 401: the fix
- Amazon SES “Email address is not verified”: the fix
- Shopify contact form not working: how to fix it
- Judge.me alternative for WooCommerce after the 2025 shutdown
- Free WooCommerce review plugins compared on the free version
- WooCommerce review reminder emails without a paid plugin
- Add Voice Recording to a Website Form
- Contact Form 7 spam: how to stop it
- WPForms not sending email: how to fix it
- Contact form emails going to spam: how to fix it
- HTML form not submitting: how to fix it
- Contact form not working: how to find the fault
- Webflow form spam: how to stop it
- Website form to Notion: how to set it up
- Website form to WhatsApp: what works and what does not
- What 1-star reviews say about AI support chatbots
- Which free form backend gives you the most submissions?
- Elfsight reviews widget not showing? Check the view limit
- Next.js contact form backend vs Server Actions
- Review stars not showing in Google search results
- How to stop duplicate form submissions
- How to see which form leads came from ChatGPT
- What happens when a form webhook fails
- When to send a review request email after an order
- How to collect video testimonials for free
- Add contact form sign-ups to Mailchimp or Klaviyo
- How to migrate from Formspree without losing submissions
- How to get a Google review link for your business
- What is a headless form backend?
- Is it safe to put a form access key in your HTML?
- AI chatbot that answers only from your website
- Minified React error #441 in Next.js
- Squarespace product reviews after Judge.me
- Accessible contact form checklist for WCAG 2.2
- How to ask a client for a testimonial by email
- How to respond to negative reviews, with examples
- 429 Too Many Requests on a contact form
- MCP server for forms in Cursor and Claude
- Can you offer a discount for a review?
- Do EU stores have to say if reviews are verified?
- Webflow form backend options compared
- How to add review schema JSON-LD to a product page
- How to turn a customer review into an Instagram post
- How to make a QR code for Google reviews
- Live chat or chatbot for a small business website
- Why people abandon your contact form halfway
- Which form backend do AI assistants pick? 54 answers
- PHP mail() not sending email, even when it returns true
- What “Failed to fetch” means, tested in three browsers
- 405 Method Not Allowed when you submit a form
- Send a contact form to more than one email address
- What is review syndication, and who needs it?
- How to save HTML form data to a database
- NetworkError when attempting to fetch resource
- Send product reviews to Google Merchant Center
- PHPMailer not working on a live server
- AI review reply generator: does it help?
- React 19 contact form with useActionState
- Astro Actions or a form backend?
- Is no-reply@wixsiteautomations.com legit?
- Where to find the Judge.me review widget code
- AI review summaries: what shoppers actually see
- Photo reviews for WooCommerce, and the GPS inside them
- Review request email templates you can copy
- Reviews in AI search: what ChatGPT and Perplexity cite
- Lead capture form with UTM tracking, built and tested
- Form design best practices, with our own form data
- Client intake form template with file upload
- What is social proof? Meaning and examples
- What is user-generated content (UGC)?
- Benefits of negative reviews for your store
- How to get your first reviews as a new store
- How to use customer reviews in your marketing
- How to get more customer reviews
- React form validation without a library, tested
- jQuery submit form with validation
- reCAPTCHA v3 setup with the server score check
- Shopify social proof that shoppers can check
- HTML file input: accept, multiple, capture and size checks
- How to add hCaptcha to a form, with the server check
- How to add invisible reCAPTCHA to a form
- Bug report form template with browser details
- What the FTC fake reviews rule bans for online stores
- How to show reviews on your homepage
- Do reviews increase sales? What the studies show
- HTML input types and what each one sends
- HTML textarea, tested in a real form
- HTML dropdown menu in a form, tested
- Do reviews help SEO? What Google says and shows
- How to add a review carousel people can read
- Product review examples that help shoppers decide
- Which trust badges actually mean something
- Customer satisfaction survey with CSAT and NPS
- JavaScript FormData and what fetch actually sends
- JavaScript form validation without a library
- Server-side form validation and what it catches
- Email validation in JavaScript, tested on 33 addresses
- Zod form validation with FormData, tested
- Store reviews vs product reviews
- How to send review requests through Klaviyo
- How to tag customer reviews by topic and mood
- Custom review form questions worth asking
- Online reputation management for small businesses
- HTML radio button groups and what they send
- HTML label tag and what screen readers hear
- HTML autocomplete attribute, tested with Chrome autofill
- HTML fieldset and legend, and what disabled leaves out
- HTML button tag and what a form button sends
- Vite contact form that still works after the build
- How to test a contact form, end to end
- How to embed a Google Form, and what it loads
- Customer feedback questions that get real answers
- How to convert a file to base64 in JavaScript
- FilePond with a form backend, and when to skip it
- Bootstrap form validation and server errors
- Tailwind form validation, tested in three browsers
- Donation form in HTML, and where the payment goes
- How to ask for a review in person or by text
- Which review sites matter for your business
- What are customer reviews, and which kinds count
- Online review statistics, checked at the source
- Best review app for Shopify and WooCommerce
- Why Gmail sends your self-hosted mail to spam
- htmx contact form that sends to another domain
- AI form builders tested, from prompt to sent form
- Headless WordPress forms with Contact Form 7, tested
- React Hook Form watch vs useWatch, and what gets sent
- Elfsight widget not working? It vanishes when views run out
- Jotform not sending emails? Check Jotform's bounce list
- Typeform not working? A white box means a blocked script
- Positive review response examples that don't sound copied
- How to remove a Google review when you can't delete it
- Google reviews not showing up? 8 causes to check in order
- Is buying Google reviews illegal? Even a review swap counts
- Which reviews can you hide? A review moderation checklist
- Average star rating: what 4.8 from 5 reviews means
- Reviews on a product page: where and how many to show
- SaaS testimonials: 3 of 27 had a number in them
- Do reviews reduce returns? Not when they're too good
- Testimonial examples for business: what makes one believable
- Testimonial questions to ask clients, by type of business
- Testimonial page design: a page or a section?
- Testimonial advertising rules: what the FTC requires
- Form submission canceled because the form is not connected
- Input type date format dd/mm/yyyy: what you can change
- How to disable textarea resize, or allow only vertical
- How to prevent Enter from submitting a form
- form.submit() vs requestSubmit(): what submit() skips
- Custom HTML checkbox CSS that doesn't break required
- Input type number maxlength not working? What to use
- How to create an HTML form, step by step
- Best form builder: free plans and branding, checked
- Best WordPress contact form plugin: 10 free ones compared
- How to increase form conversion rate: start with the count
- Form backend vs form builder: which one do you need?
- WordPress contact form not sending email? 3 plugins tested
- Contact Form 7 webhook? Turning it on switched our email off
- Gravity Forms webhook: what it sends and the URLs it rejects