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().Point any HTML form at one endpoint. 500 free submissions — no card, no time limit — and unlimited forms.
Create free accountQuick 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
checkedattribute. - Selects go back to the option with the
selectedattribute, 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 = ""; });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.