< Modern HTML >

< button >

Not a link.

The button element has picked up a handful of new capabilities over the last few years. Before getting to those, here is what the element already does the moment you type <button>: keyboard activation, focus handling, the platform focus ring, disabled semantics, form submission participation, and the correct assistive technology role.

Built-in with native HTML

The type attribute, precisely

Three values: submit (the default), reset, and button. A button inside a <form> with no explicit type behaves as type="submit".

<form>
  <button>Save</button>
  <button type="button">Cancel</button>
</form>

The first button submits the form. The second does not. Setting type explicitly on every button inside a form is one way to make the behavior unambiguous at the markup level. For an in-house button component, one option is to default the component's type to "button", leaving callers to opt into submit when submission is the intent. When a component passes type through without setting its own default, HTML's own default applies: submit inside a form, otherwise button.

Form-associated attributes: letting a button override the form

A button inside a form can override the form's submission behavior on a per-button basis. Five attributes do the work:

Consider a form with two submit paths: a "Save draft" button that posts to a draft endpoint and skips validation, and a "Publish" button that submits to the primary endpoint with validation intact. Both buttons live in one form. The markup:

<form action="/publish" method="post">
  <input name="title" required>
  <textarea name="body" required></textarea>
  <button type="submit" formaction="/draft" formnovalidate>Save draft</button>
  <button type="submit">Publish</button>
</form>

Invoker commands: declarative triggers for dialogs, popovers, and more

The button element is the declarative trigger for several platform features that used to require a script.

<button popovertarget="menu" popovertargetaction="toggle">Options</button>
<div id="menu" popover>...</div>

The invoker commands API (command and commandfor) is the newest of these. Worth checking current browser support before relying on it in production.

Composite patterns that call for <button>

Patterns where the button element is the right choice and other elements would break the pattern:

disabled vs aria-disabled

Two attributes, two different behaviors. Which one fits depends on whether the button should still be reachable.

Behavior disabled aria-disabled="true"
Tab-focusable No Yes
Click fires No Yes (the handler must block)
Announced as disabled Yes Yes
Participates in form submission No Yes

aria-disabled is useful when the button needs to stay focusable so the user can inspect it, read a tooltip, or see a validation message explaining why it's disabled. The handler then checks the attribute and blocks the action. disabled is for controls that are genuinely inert, with no need to be reached.

Already HTML-available

Patterns that HTML handles natively, which are often rebuilt in JavaScript:

Sizing

The 44 by 44 CSS pixel minimum for an interactive target traces back to WCAG 2.5.5 (Target Size, Level AAA) and the Apple Human Interface Guidelines. WCAG 2.2 added success criterion 2.5.8 at Level AA, which is 24 by 24 with spacing exceptions. For a site targeting AA, 24 is the floor. 44 remains a solid default for touch interfaces.


Reference:

WHATWG
the-button-element
caniuse.com
mdn-html_elements_button
MDN Docs
Web/HTML/Element/button
WAI-ARIA APG
Button Pattern
Menu Button Pattern
Open UI
Invoker Commands explainer