splitforms.com
← Back to the journal

How to Clear a Form After Submit in JavaScript (form.reset())

Clear a form after submit with form.reset() after fetch, why reset() restores value attributes instead of blanking, and React and Vue patterns.

Start free — 500 submissionsSee pricing →No card, no time limit. Pro is $5 per month.
Short answer
Call form.reset() after await fetch(...), and only when res.ok is true. reset() restores each field's default (its value attribute, checked attribute or selected option), so it does not always blank fields. In React, reset your state instead, because controlled inputs ignore reset().
Try it on your own form

Point any HTML form at one endpoint. 500 free submissions — no card, no time limit — and unlimited forms.

Create free account

Quick answer: reset after a successful fetch

Stop the normal page reload, send the fields with FormData, and clear the form only when the server says the request worked:

const form = document.querySelector("#contact");

form.addEventListener("submit", async (e) => {
  e.preventDefault();

  const res = await fetch(form.action, {
    method: "POST",
    body: new FormData(form),
  });

  if (res.ok) {
    form.reset();
  }
});

Read the fields before you reset. new FormData(form) copies the values at that moment, so calling reset() later does not change what was sent. For a full send-to-email walkthrough, see how to send form data to email with JavaScript fetch.

What reset() really does (and why it is not "blank")

form.reset() does the same thing as a <button type="reset">. It puts every control back to its default state:

  • Text inputs and textareas go back to the value attribute (or the textarea's inner text).
  • Checkboxes and radios go back to whatever has the checked attribute.
  • Selects go back to the option with the selected attribute, or the first option if none has it.

So an input rendered as <input name="city" value="Toronto"> goes back to Toronto, not to an empty box. That is the usual reason for "form.reset() not working". If you want those fields empty, blank them yourself after the reset, or drop the value attribute and use placeholder for hint text:

form.reset();

// blank fields that were rendered with a value attribute
form.querySelectorAll("input[value]:not([type=hidden]):not([type=checkbox]):not([type=radio])")
  .forEach((el) => { el.value = ""; });

Hidden inputs, selects and file inputs

reset() leaves type="hidden" inputs alone, because a hidden input's value is its default. That is good news: your access_key, redirect URL or campaign field stays in place for the next submit.

<input type="hidden" name="access_key" value="YOUR_KEY" />  <!-- kept -->
<input type="file" name="attachment" />                      <!-- cleared -->
<select name="topic">
  <option>General</option>                                    <!-- back to this -->
  <option>Support</option>
</select>

File inputs are cleared by reset(), so the user will not resend the same upload by accident. If you changed a hidden field with JavaScript during the session, it keeps that new value too, so set it again yourself if it needs to change.

Don't reset when the request fails

Clearing a long message and then showing "something went wrong" is the fastest way to lose a lead. Only reset on success, and keep the text on errors:

try {
  const res = await fetch(form.action, { method: "POST", body: new FormData(form) });
  if (!res.ok) throw new Error("Request failed: " + res.status);
  form.reset();
  showStatus("Thanks! Your message was sent.");
} catch (err) {
  showStatus("Sorry, that did not send. Your text is still here, please try again.");
}

Disable the submit button while the request runs so a double click does not send the form twice. The full pattern is in how to prevent duplicate form submissions.

React: reset the state, not the DOM

Controlled inputs (value={state} plus onChange) ignore form.reset(): React renders the state value again. Reset the state instead:

const initial = { name: "", email: "", message: "" };
const [values, setValues] = useState(initial);

async function onSubmit(e) {
  e.preventDefault();
  const res = await fetch("/api/contact", {
    method: "POST",
    body: new FormData(e.currentTarget),
  });
  if (res.ok) setValues(initial);
}

For uncontrolled inputs (defaultValue or no value at all), keep a ref on the form and call the DOM method:

const formRef = useRef(null);
// after a successful fetch:
formRef.current.reset();

<form ref={formRef} onSubmit={onSubmit}>...</form>

With React 19 form actions (<form action={fn}>), React resets uncontrolled fields automatically once the action finishes, so you often need no reset code at all. See the React 19 form actions contact form. If you use React Hook Form, use its own reset(), covered in React Hook Form reset.

Vue: reset the reactive object

With v-model, the data is the source of truth, so reset the reactive object after a successful request:

const initial = () => ({ name: "", email: "", message: "" });
const form = reactive(initial());

async function onSubmit() {
  const res = await fetch("/api/contact", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(form),
  });
  if (res.ok) Object.assign(form, initial());
}

Show a success message and move focus to it

After reset() the form looks empty, and some users will wonder if anything happened. Show a clear message in a role="status" element so screen readers announce it, and move focus there:

<p id="form-status" role="status" tabindex="-1"></p>

<script>
function showStatus(text) {
  const status = document.getElementById("form-status");
  status.textContent = text;
  status.focus();
}
</script>

FAQ

Why does form.reset() not clear my input?

reset() restores each field to its default value, which is the value attribute in the HTML, not an empty string. If the input was rendered with value="x", reset() puts x back. In React, controlled inputs take their value from state, so reset() changes the DOM for a moment and React renders the state value again. Clear the state, or set el.value = '' for fields that have a value attribute.

How do I clear a form after submit with fetch?

In the submit handler call e.preventDefault(), send the data with await fetch(form.action, { method: 'POST', body: new FormData(form) }), and call form.reset() only if res.ok is true. If the request fails, keep the user's text and show an error instead.

Does form.reset() clear hidden inputs?

No. A type=hidden input has no separate default value, so reset() leaves it as it is. That is useful: an access_key or redirect field stays in place for the next submit. File inputs, on the other hand, are cleared by reset().

How do I clear an input after submit in React?

For controlled inputs, reset the state, for example setValues(initialValues). For uncontrolled inputs, keep a ref on the form and call formRef.current.reset(). With React 19 form actions (<form action={fn}>), React resets uncontrolled fields automatically after the action finishes.

References: MDN: HTMLFormElement.reset() and HTML spec: resetting a form.

Need somewhere to send the form? A form to email endpoint from splitforms takes the FormData POST above and emails each submission to you, so the only code you write is the fetch and the reset.

Related articles

More practical guidance from tutorials.

Browse the journal →
Tutorials

How to Remove the Arrows From a Number Input (CSS, Tailwind, React)

Hide the number input spin buttons with ::-webkit-inner-spin-button and appearance: textfiel…

7 min readRead →
Tutorials

How to Change the Autofill Background Color of an Input (CSS, Tailwind)

Remove Chrome's yellow autofill background with input:-webkit-autofill, inset box-shadow, -w…

7 min readRead →
Tutorials

input type=number maxlength Not Working? 4 Fixes That Work

Why maxlength is ignored on input type=number, plus four fixes: min/max, oninput slice, text…

8 min readRead →

Explore this topic

Start with the overview, then move into focused guides.

OverviewContact Forms for Every FrameworkStart here →GuideContact Form for Next.jsRead →GuideContact Form for ReactRead →GuideContact Form for VueRead →ReferenceContact form guideOpen →

Building forms with ChatGPT, Claude, Cursor, or v0? Connect the native MCP server and give your agent a production form backend.

Explore the MCP server →

Give your form a production backend.

One endpoint adds delivery, spam filtering, storage, and integrations. Start with 500 free submissions — no card, no time limit.

Create free accountRead the docs →
Secure checkoutSSL encryptionPrivacyProtected
VISAAMERICANEXPRESSstripe