The HTML formnovalidate attribute
A submit button with formnovalidate sends its form unchecked, which lets a Save draft button store unfinished work. Any other submit button still runs every check, unless the form has novalidate. Inputs of type submit or image accept the attribute too.
Overview
The HTML formnovalidate attribute lets one submit button send its form without validation. It is useful for save buttons, which let people store unfinished work while the button that completes the form still checks every field.
The validator.nu checker rejects formnovalidate on a type="button" or type="reset" <button>, where it has no effect anyway. The same goes for an <input> of type button.
Pressing a Save draft button with name="intent" and value="draft" adds intent=draft to the submission, and a Publish button's value stays out. That one entry lets your server tell a draft from a finished post.
The attribute covers a single button. To skip validation however the form is submitted, put novalidate on the form instead.
Syntax
<form action="/posts" method="post">
<label for="title">Title</label>
<input id="title" name="title" required>
<button name="intent" value="publish">Publish</button>
<button name="intent" value="draft" formnovalidate>Save draft</button>
</form>
Values
| Value |
|---|
| On a submit button, presence alone skips validation for that button. |
Example
<form id="post">
<label for="title">Title</label>
<input id="title" name="title" required><br>
<label for="body">Post</label>
<textarea id="body" name="body" rows="2" cols="24" required></textarea>
<p>
<button name="intent" value="publish">Publish</button>
<button name="intent" value="draft" formnovalidate>Save draft</button>
</p>
</form>
<p id="out" role="status" style="overflow-wrap:anywhere"></p>
<p>Leave the fields empty and press each button.</p>
<script>
const form = document.getElementById('post');
const out = document.getElementById('out');
form.addEventListener('invalid', function () {
out.textContent = 'Publish was blocked because a required field is empty.';
}, true);
form.addEventListener('submit', function (e) {
e.preventDefault();
const data = new URLSearchParams(new FormData(form, e.submitter));
out.textContent = e.submitter.textContent + ' would send ' + data;
});
</script>
Best practices
- Check what Enter does once a form has a formnovalidate button. If Save draft comes first in the source, Enter skips validation, so keep Publish ahead of it.
- Have the server relax its required-field checks only when the submitted intent says draft. A formnovalidate button sends empty text fields as empty strings, such as
title=, and leaves out unticked checkboxes. - Send drafts to their own URL by adding formaction to the same button, such as
formaction="/drafts". The Publish button then keeps the form's action. - For an autosave timer, use
form.requestSubmit(draftButton). It fires your submit handler and skips validation, the same as a click on Save draft.























