Buttons: submit, reset and button

Three button types, one attribute, and a default that causes more accidental submissions than any other rule in HTML.

Concept

HTML has two ways to make a button: the button element and input with a button type. The button element is better in almost every case, because it can contain markup - an icon, a span, formatted text - while an input can only carry a plain string.

The three types

TypeDoes
submitValidates and submits the form. The default inside a form.
resetClears every field back to its initial value.
buttonDoes nothing on its own. For scripted actions.
<button type="submit">Send application</button>
<button type="reset">Clear the form</button>
<button type="button" id="preview">Preview</button>

The default that catches everyone

A button with no type inside a form defaults to type="submit". So this innocent looking markup submits the form every time it is pressed:

<form action="/save" method="post">
  <input name="title">
  <button onclick="addRow()">Add another row</button>   <!-- submits! -->
</form>

The script runs, then the form submits and the page navigates away. The usual symptom is my button works for a split second and then the page reloads.

<button type="button" onclick="addRow()">Add another row</button>

Write type on every button. It is two words and it removes an entire category of bug.

button versus input

<!-- can contain markup -->
<button type="submit">
  <svg aria-hidden="true">...</svg>
  <span>Save changes</span>
</button>

<!-- plain text only, from the value attribute -->
<input type="submit" value="Save changes">

Use button. The only historic reason to prefer input was consistency in very old browsers, which no longer matters.

Named submit buttons

A submit button can carry a name and a value, and only the button actually pressed is submitted. This is a clean way to give one form two outcomes without any JavaScript.

<form action="/post" method="post">
  <textarea name="body"></textarea>

  <button type="submit" name="action" value="draft">Save as draft</button>
  <button type="submit" name="action" value="publish">Publish</button>
</form>

The server receives action=draft or action=publish and branches on it.

Overriding the form from a button

A submit button can override several of the form attributes:

<button type="submit" formaction="/save-draft">Save draft</button>
<button type="submit" formmethod="get">Preview</button>
<button type="submit" formnovalidate>Save without checking</button>

formnovalidate is the genuinely useful one: it lets a Save draft button skip validation while Publish enforces it.

Why reset is almost always wrong

type="reset" clears the whole form with no confirmation and no undo. It sits next to the submit button, looks identical, and destroys ten minutes of typing when pressed by mistake. Nobody wants it - readers who want to start again close the tab.

Leave it out. If a form genuinely needs a clear action, make it a scripted button with a confirmation step.

Disabled buttons

A disabled submit button is a common pattern and a poor one. It is not focusable, so a keyboard user cannot reach it to find out why it is disabled; screen readers may skip it entirely; and the reader is given no explanation.

<!-- better: always enabled, explains the problem on submit -->
<button type="submit">Create account</button>

Let the reader press it and show them what is wrong. If a button must be disabled, keep it focusable and describe the condition:

<button type="submit" aria-disabled="true" aria-describedby="why-disabled">
  Create account
</button>
<p id="why-disabled">Accept the terms before creating an account.</p>

aria-disabled announces the state without removing the element from the tab order; the script then ignores the click.

Buttons that are not buttons

<!-- wrong: not focusable, no keyboard activation, no role -->
<div class="btn" onclick="save()">Save</div>

<!-- wrong: a link that navigates nowhere -->
<a href="#" onclick="save()">Save</a>

<!-- right -->
<button type="button" onclick="save()">Save</button>

A real button gives you focusability, activation with both Enter and Space, the correct role, and disabled state handling. Recreating all of that on a div takes twenty lines of script and is usually done wrong.

Important rules

  • A button inside a form defaults to type="submit".
  • Only the pressed submit button is submitted, and only if it has a name.
  • Enter in a text field activates the first submit button in the form.
  • Buttons are focusable by default; do not add tabindex.
  • A button must not contain interactive content such as a link or another button.
  • type="reset" resets to the initial values, not to empty.

Common mistakes

  • Omitting type and submitting a form by accident.
  • Keeping a reset button next to submit.
  • Using a div or a dead link as a button.
  • Disabling the submit button until the form is valid, with no explanation of why.
  • Icon only buttons with no accessible name.
  • Two submit buttons with no name, so the server cannot tell which was pressed.

Best practices

  • Always write type.
  • Use the button element, not input.
  • Label buttons with a verb and an object: Send enquiry, not Submit.
  • Give icon only buttons an aria-label and mark the icon aria-hidden.
  • One primary action per form, visually distinct from secondary actions.
  • Use formnovalidate for a save draft action.
  • Keep tap targets at least forty four pixels tall.

Practice

  1. Put a button with no type inside a form with a click handler and observe the page reload. Fix it.
  2. Build a form with Save draft and Publish buttons sharing one name, and branch on the value.
  3. Add formnovalidate to the draft button and confirm required fields no longer block it.
  4. Replace a div based button with a real one and list everything you gained.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.