Skip to content
AgileLogics
5 min read

Buttons and Submitting Forms

Prerequisites: Checkboxes, radios, selects, and text areas

The button element

<form action="/cart" method="post">
  <input type="hidden" name="product" value="rye-loaf">
  <label for="qty">Quantity</label>
  <input id="qty" name="qty" type="number" min="1" value="1">
  <button type="submit" name="action" value="add">Add to cart</button>
  <button type="submit" name="action" value="save" formaction="/wishlist">Save for later</button>
  <button type="reset">Reset</button>
</form>

button has three types:

  • submit — submits the form. This is the default inside a form.
  • button — does nothing on its own; used with JavaScript.
  • reset — resets every field to its initial value. Rarely helpful — it's easy to click by accident and lose everything.

A submit button's own name/value is sent with the form, so the server can tell which button was pressed. formaction (and formmethod, formnovalidate) override the form's settings for one button.

Always set type on script buttons

<form action="/profile" method="post">
  <label for="bio">Bio</label>
  <textarea id="bio" name="bio"></textarea>
  <button type="button" id="preview">Preview</button>
  <button type="submit">Save</button>
</form>

Without type="button", clicking "Preview" would submit the form — a classic bug.

Buttons vs links

  • A link (a href) goes somewhere — another page or place.
  • A button does something — submits, opens a menu, plays a video.

Keyboard users expect Enter to follow links and Space or Enter to press buttons, and screen readers announce them differently. Styling a link to look like a button is fine; using a div or a link with href="#" as a button is not.

Buttons with icons

<button type="button" aria-label="Close">
  <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M2 2 14 14M14 2 2 14" stroke="currentColor" stroke-width="2"/></svg>
</button>

An icon-only button needs an accessible name — here aria-label — or screen readers just say "button".

What happens on submit

  1. The browser runs built-in validation (required, type="email", ...) and stops with a message if something is wrong (Level 2 covers this in depth).
  2. It collects every named, enabled control's value — skipping unticked checkboxes and disabled fields.
  3. It sends a request to action with method, and shows the page the server responds with.

disabled fields are skipped; use readonly for a field that can't be edited but should still be submitted.

Practice

Why is this a problem, and how do you fix it?

<form action="/comments" method="post">
  <textarea name="comment" aria-label="Comment"></textarea>
  <button id="emoji">😀 Insert emoji</button>
  <button>Post</button>
</form>
Show solution

Both buttons default to type="submit", so clicking the emoji button posts the half-written comment. Add type="button" to it:

<form action="/comments" method="post">
  <textarea name="comment" aria-label="Comment"></textarea>
  <button type="button" id="emoji">😀 Insert emoji</button>
  <button type="submit">Post</button>
</form>

Related developer tools