What <button> is
<button> represents a control whose activation invokes an action.
The action can be: submit a form, reset a form, run a JavaScript
handler, or — since 2024 — invoke a command on another element
declaratively.
<button type="submit">Save</button>
<button type="reset">Discard</button>
<button type="button">Toggle theme</button>
The default type is submit if the button is inside a <form>.
This default catches authors out: a stray <button> inside a form
submits on Enter from any text input, not the intended action.
Always set type="button" for non-submitting buttons inside a
form.
The three roles of <button>
type | What it does |
|---|---|
submit | Submits the containing form. Default inside a form. |
reset | Resets the containing form to initial values. Rare in modern UI. |
button | Inert until JS attaches a handler. The “regular button”. |
Outside a form, the default type is also submit per the spec,
but with no form to submit it is effectively a no-op. Setting
type="button" is still recommended for clarity.
The 2024 command and commandfor attributes
The HTML 2024 living standard added a declarative invocation primitive: a button can target another element on the page and issue a named command, no JavaScript required.
<button commandfor="my-dialog" command="show-modal">Open dialog</button>
<dialog id="my-dialog">…</dialog>
<button commandfor="my-popover" command="toggle-popover">More</button>
<div id="my-popover" popover>…</div>
The pre-defined commands are:
show-modal,close— for<dialog>.show-popover,hide-popover,toggle-popover— forpopoverelements.- Custom commands prefixed with
--for author-defined behaviour.
Reached cross-engine availability in Chromium 135 (early 2025) and is in development in WebKit and Gecko. About 60% of new modal/popover code in greenfield projects uses the declarative form, per the State of HTML 2024 survey.
Form integration attributes
Inside a <form>, <button type="submit"> accepts attributes
that override the form’s defaults just for that submit:
formaction— submit to a different URL.formmethod—getorpost.formenctype— different encoding.formnovalidate— skip native validation.formtarget— different target window.nameandvalue— pair sent only when this button submits.
The pattern is rare but powerful: a single form with separate “Save draft” and “Submit for review” buttons, each routing to a different endpoint, requires no JS.
Accessibility
<button> exposes role="button" and a default keyboard
contract:
- Enter and Space activate.
- Tab focusable in document order.
- Disabled buttons are removed from focus order; a button
expressing inactive state without leaving focus order should
use
aria-disabled="true"instead. - Default
:focus-visibleoutline (varies by engine).
For an icon-only button, provide an accessible name:
<button type="button" aria-label="Close">×</button>
The × glyph is announced as “multiplication” without the label.
Common pitfalls
<a href="#" onclick="...">instead of<button>. Adds a spurious URL hash, breaks Cmd-click “open in new tab”, confuses screen readers.<div role="button">. Misses the keyboard contract; needs manualtabindex, key handler, and disabled support.<button>inside an<a>or vice versa. Invalid HTML and breaks AX exposure.typeomitted inside a form. Submits unintentionally.- Loading-state replaces button text but keeps the click
handler enabled. Add
disabled(oraria-disabledplus a guarded handler) to prevent double-submit. <button>with mixed content (text + icon) and noaria-labelworks fine; the accessible name is the concatenated text. The problem is only icon-only buttons.
Cross-engine support
<button> and its three type values reached interop two decades
ago. Form-association attributes (formaction etc.) reached
interop in 2017. The 2024 command / commandfor attributes are
Chromium 135+; WebKit and Gecko targets in 2025 per
wpt.fyi/html/semantics/forms/the-button-element.
caniuse for <button command>
reports about 75% global support in early 2025.
Further reading
- HTML Living Standard, §4.10.6 The button element.
- The Open UI invokers explainer
is the design rationale for
command/commandfor. - Manuel Matuzović’s
<button>accessibility deep-dive is a dense walk-through.