Button
UI pattern
button role, an accessible name, and a reliable disabled state, and keyboard users can reach and activate it.A button differs from a link, which navigates to another page, view, or resource rather than performing an action on the current page.
Sighted users learn what a button does from its label, its visual presentation, and its context. Assistive technology users depend on button labels, semantics, properties, and states being conveyed to the assistive technology they use.
The following HTML elements are semantic buttons that natively convey their button role and other essential information to assistive technologies: <button>, <input type="button">, <input type="submit">, <input type="image">, and <input type="reset">.
Any of the native HTML semantic buttons automatically conveys its button role, name, and disabled state to assistive technology and is keyboard operable. Native HTML buttons go beyond what WCAG success criteria strictly require, so use them whenever possible.
A user can activate a native HTML button in many ways: by pointing and clicking with a mouse or other pointing device, by tapping a touch screen, by issuing a voice command through assistive technology that supports it, or by pressing the Enter or Space key. Each of these results in a click event that JavaScript can handle to perform the action.
Activating a button with any kind of pointing device can be canceled. The click event occurs when the user releases the mouse button, lifts the finger that tapped the touch screen, or completes whatever action their device requires to point and "click." To cancel, the user moves the pointer off the button before releasing it.
Current accessibility standards do not require a way to cancel button activation with a keyboard, but native HTML buttons provide one. The Enter key activates a button as soon as it's pressed. The Space key doesn't activate a button until it's released, and moving focus away from the button while holding the key down cancels the activation.
The Examples section discusses the ARIA attributes and JavaScript a generic HTML element needs to emulate a native HTML button.
This article covers the base accessibility requirements of buttons, however they're used. Some specialized button applications have additional accessibility requirements. Their entries are listed in Related Patterns.
When to Use
Use a button when:
- The control triggers an immediate action on the current page, such as submitting a form, saving, opening or closing a dialog, or confirming or canceling a choice.
Don't use a button when:
- The control takes the user to another page, view, or resource. Use a link so assistive technology users are aware that acting on it will cause a change of context.
- The control lets the user enter a value or select one from a set. Use a combobox, listbox, or another form of input.
Activating a button should never cause an unexpected change of context.
Examples
Code in this section is meant to demonstrate techniques rather than requirements and lacks features needed in a production application.
A native HTML button, such as the one in the following example, is accessible by default. The JavaScript that performs its action only needs to handle the click event for the button to be operable by all users. It's in the tab order and keyboard operable unless its disabled attribute is set.
Native button HTML
<button id="save-button">Save changes</button>Native button JavaScript
document.getElementById('save-button').addEventListener(
'click', () => { /* Save changes */ }
)A custom button requires additional attributes and JavaScript to duplicate the built-in accessibility of the <button> element, as in the following simplified example.
To emulate a native HTML button, this custom button requires several code additions that come for free with <button>:
- The attribute
role="button"is set to let assistive technology users know that the element is a button. - The attribute
tabindex="0"places the button in the tab order, allowing keyboard users to focus on it. - The "Save changes" action is handled on the
clickevent. - Keyboard event handlers allow button activation by triggering a
clickevent with the Enterkeydownor Spacekeyupevents. - JavaScript can disable the button with
saveButton.disabled = trueand re-enable it withsaveButton.disabled = false. - Whenever the button is disabled, its action is prevented, the attribute
aria-disabled="true"is set, and the button is removed from the tab order.
Custom button HTML
<div id="save-button" role="button" tabindex="0">Save changes</div>Custom button JavaScript
class CustomButton {
#element;
constructor(element) {
this.#element = element;
this.#initialize();
}
#saveChanges() {
/* code to save changes */
}
#initialize() {
this.#element.setAttribute("role", "button");
this.#element.tabIndex = 0;
this.#element.addEventListener("click", (event) => {
if (this.disabled) {
event.preventDefault();
event.stopImmediatePropagation();
return;
}
this.#saveChanges();
})
this.#element.addEventListener("keydown", (event) => {
if (this.disabled) return;
if (event.key === "Enter") {
event.preventDefault();
this.#element.click();
}
else if (event.key === " ") {
// prevent default page scroll
event.preventDefault();
}
})
this.#element.addEventListener("keyup", (event) => {
if (this.disabled) return;
if (event.key === " ") {
event.preventDefault();
this.#element.click();
}
})
}
get disabled() {
return this.#element.getAttribute("aria-disabled") === "true";
}
set disabled(trueOrFalse) {
const disable = Boolean(trueOrFalse);
this.#element.setAttribute("aria-disabled", String(disable))
this.#element.tabIndex = disable ? -1 : 0;
}
}
const saveButton = new CustomButton(
document.getElementById('save-button')
);Structure and Semantics
A button is an interactive element that conveys its purpose to assistive technology through the button role and its accessible name, which together tell users what the button does and how to use it.
A button has no structure. The element <input type="button"> is defined by its attributes. A <button> element can have content, but assistive technologies use that content only to compute the button's accessible name. They treat the subtree of any element with the button role as presentational.
ARIA attributes can add semantic information to convey special-purpose properties or state to assistive technology:
| Attribute | Purpose |
|---|---|
aria-controls | Identifies an element the button controls |
aria-disabled | Reports the button's disabled / enabled state |
aria-expanded | Reports the visibility state of the content the button controls |
aria-haspopup | Reports the presence and nature of a popup the button controls |
aria-label | Provides an accessible name when text content can't provide one |
aria-pressed | Reports the pressed state of a toggle button |
Role
A button must expose the button role to assistive technology so that users know its purpose and how they can interact with it.
The HTML <button> and <input type="button"> elements expose the button role implicitly, requiring no additional ARIA. When you have to build a button from a different element, such as a non-semantic element or a semantic element that allows the button role, set role="button" on it explicitly.
Without the button role, screen readers announce a button as plain, non-interactive content or, with a different role, as the wrong kind of element. Users won't know its purpose or how to interact with it.
The following elements implicitly carry the button role:
<button>and<input type="button">can be used anywhere on a web page.<input type="image">and<input type="submit">can be used to submit a form.<input type="reset">can be used to reset a form.
Button has the correct role
Reported as: Element has incorrect role
A button must carry the button role.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Button role is applied to the interactive element
Reported as: Incorrect root element
Sanity check. Evinced checks that the button role sits on the selected element, the one users focus and operate, rather than on one of its descendants. This check runs on every UI pattern, not only on buttons.
The button role should sit on the same element that receives focus and handles activation.
When the role sits on a descendant while a wrapper takes focus or handles the click, screen readers announce a button that isn't the element users operate, and keyboard users may reach a control that doesn't respond to Enter or Space.
Put the role, the accessible name, the ability to focus, and the activation handling on that one element, and keep any wrapper free of roles and handlers. If the test selected a wrapper by mistake, select the button itself and run the test again.
Button Name
By default, a button is named by its text content, and that name should say what the button does. Without a meaningful name, screen readers announce only "button," and users can't know what it does or tell it apart from other buttons.
Has an accessible name
Reported as: Accessible name
A button must have an accessible name that identifies what it does.
Give the button a name through visible text, an image's alt text, or an aria-label attribute, and keep the name short and specific to the action it performs.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Disabled
A button must convey its disabled state to assistive technologies.
Avoids conflicting disabled states
Reported as: Conflicting disabled values
A button must declare its disabled state one way only: the disabled attribute on a native <button> or <input type="button">, or aria-disabled on a custom button.
When a native button carries aria-disabled instead of disabled, it stays operable and in the tab order while assistive technology reports it as disabled. When both attributes are set and disagree, assistive technology can report a state the browser doesn't enforce. Either way, screen reader users are told the wrong thing about whether the button works.
Use disabled alone on a native button and aria-disabled alone on a custom button, removing it or setting it to false when the button is enabled again.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Custom button uses aria-disabled rather than disabled
Reported as: Element does not support the disabled attribute
A button built from an element that does not natively support the disabled attribute must convey its disabled state with aria-disabled instead.
When the disabled attribute is applied to an element that doesn't support it, such as a custom button built from a <div> or <span>, browsers ignore it. The button stays operable even though it looks disabled, so keyboard and screen reader users can still trigger an action meant to be unavailable. Use aria-disabled="true" instead, and block activation in the button's event handlers while it's disabled.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Disables only elements that support it
Reported as: Element type does not support disabled state
An element in a button must carry disabled or aria-disabled only when its role supports a disabled state.
When the state sits on an element whose role has none, such as a wrapper, a list item or a heading, assistive technology may drop it or report it on something users can't operate, while the control that really is unavailable is still reported as available.
Remove the attribute from that element, and set the disabled state on the control itself, using an element or role that supports it, such as a native <button>.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Forbidden Interactive Children
Nested interactive elements create ambiguity for all users, who can't be certain which element will respond to their interaction.
Interactive elements are not nested
Reported as: Forbidden interactive children; Nested interactive elements
A button must not contain or be nested inside another interactive element, such as a link or other button.
A button has no accessible children. An interactive element nested inside it is presentational, so screen reader users can't perceive or operate it as a control.
Don't nest interactive elements.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Relationships
Buttons often control other elements to create user interfaces. When a button's presentation conveys a relationship to another element, the button should also convey it to assistive technology by setting aria-controls to the ID of the controlled element.
aria-owns
A button is a single control, not a container. Its children are presentational, so nothing inside a button reaches assistive technology except as part of its accessible name.
Avoids aria-owns
Reported as: Avoid aria-owns
General check. Evinced checks that the button doesn't use aria-owns to claim elements elsewhere in the document as its children. This check runs on every UI pattern, not only on buttons.
A button should not use aria-owns.
When a button owns an element, that element becomes one of the button's children, and a button's children are presentational. Assistive technology users perceive the owned element only as part of the button's name and can't operate anything interactive inside it.
Remove aria-owns and keep the content outside the button. When the button operates that content, reference it with aria-controls instead.
Operation
A button must be operable with both a pointer and a keyboard. Clicking or tapping the button activates it. On a keyboard, the Tab key moves focus to and away from a button, and pressing Enter or Space activates it.
Semantic HTML buttons provide this keyboard behavior automatically. A custom button built with role="button" must reproduce it: Add tabindex="0" so the element joins the tab order, and add event listeners to enable activation with the Enter or Space key. By convention, a button is activated on an Enter keydown event and a Space keyup event.
Focus Sequence
A button must be in the tab order and reachable with the Tab key when it's enabled, and should be removed from the tab order when it's disabled.
Button is reachable by keyboard
Reported as: Keyboard accessible
A button must be reachable in the keyboard tab order.
When the button is built from markup that isn't focusable, such as a <div> or <span>, it may be clicked with a pointer, but keyboard users can't reach it or operate it.
A native <button> element is focusable by default. A custom button needs a tabindex="0" attribute to join the tab order.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Button is removed from tab order when disabled
Reported as: Disabled element focusable
An HTML <button> element is removed from the tab order when it's disabled, and a custom button should be too. When a disabled button stays in the tab order, keyboard users land on a control they can't activate. Screen reader users are told the button is disabled, but the tab stop may provide no benefit.
For a custom button, set tabindex="0" when it's enabled and set tabindex="-1" when aria-disabled="true" is set.
Severity: Minor
The interactive element is in the tab order
Reported as: Focusable offset
The element that is actionable and carries the button role must be the element that receives focus, not one of its descendants.
When a descendant takes focus instead, keyboard users can tab to the control but may not be able to activate it with Enter or Space.
HTML <button> and <input> elements that aren't disabled are in the tab order by default. For a custom button, set tabindex="0" on the element that triggers the action and carries the button role.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Keyboard Activation
Unless explicitly prevented, a click event can be triggered on any HTML element by someone using a mouse or other pointing device. Keyboard users can activate only native HTML interactive elements. Some elements, such as <a href="some-uri">, are activated with the Enter key, while others, such as <input type="checkbox">, are activated with the Space key. Unless it's disabled, a button activates with either the Enter or Space key.
For an interactive element, Enter and Space carry subtly different semantics: The Enter key most often triggers a do action, while the Space key generally triggers a select action, and a button honors both.
A button is activated on an Enter keydown event but on a Space keyup event so that a user can cancel the select action. To cancel it, the user tabs away from the button while holding the Space key down.
Operable by keyboard
Reported as: Button not activated by keyboard
Keyboard users must be able to focus on and activate a button. Otherwise, they can't use the interface.
HTML elements that implicitly carry the button role, such as <button> and <input type="button">, are keyboard operable. Any other element requires JavaScript event listeners for keyboard events that either perform the action or create a click event that triggers the action.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Responds to Enter and Space
Reported as: Button may not be activated by keyboard
A button must respond to both the Enter key and Space.
When a button's script handles clicks but shows no handling for Enter or Space, keyboard users may press the keys a button promises and get no response. Whatever the button does is then out of their reach.
Use a native <button>, which handles both keys. On a custom button, handle Enter and Space in a keydown listener and run the same action a click runs.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Ignores keyboard when disabled
Reported as: Disabled button keyboard activation
A button that reports itself as disabled should reject keyboard activation.
When a custom button carries aria-disabled="true" but the Enter or Space key still triggers its action, screen reader users may be confused or lose trust in the interface. When possible, use the HTML <button>, which blocks interaction automatically when disabled is set. Otherwise, block activation with JavaScript whenever aria-disabled="true" is set on a custom button.
Severity: Serious
Button activates with Space key
Reported as: Button requires space key activation
A custom button must activate with the Space key, as a <button> element does, not just with the Enter key.
Users who expect Space to work as it does for every other button may conclude the control is unresponsive or, if they expect the ability to cancel a choice after pressing Space down, may find they can't.
Add a Space keyup event handler to activate a custom button, or use a native <button> element.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Event Listener Type
When script in a button responds to keys, it listens for keydown or keyup. The keypress event is deprecated, and browsers don't fire it for many keys, including the arrow keys, Home, End and Escape.
Avoids the keypress event
Reported as: Deprecated keypress listener
A button's key handling should use keydown or keyup, not keypress.
When a handler listens for keypress, keys the browser doesn't send through that event go unanswered, and keyboard users find the button ignoring keys it's meant to respond to.
Replace each keypress listener with a keydown listener, and read the key from event.key.
Severity: Minor
FAQ
Which WCAG success criteria do the button issues relate to?
Most button issues relate to 4.1.2 Name, Role, Value: the button role, an accessible name, a correctly conveyed disabled state, and no nested interactive elements. Reaching a button by keyboard, focus landing on the element that carries the role, and activating it with Enter and Space relate to 2.1.1 Keyboard.
Two criteria map to no WCAG success criterion and are best practices: removing a disabled button from the tab order, and ignoring the keyboard when a button is disabled.
Why are some button issues marked as Critical and others as Minor?
Severity reflects how much an issue gets in users' way. Critical issues stop users outright: a button with no role or name, or one that keyboard users can't reach or activate.
Serious issues mislead or confuse users, such as a wrong disabled state, nested interactive elements, or a disabled button that still responds to the keyboard. Minor issues break a convention without blocking the task, such as a custom button that ignores the Space key, focus that lands inside the button rather than on it, or a disabled button left in the tab order.
Two checks carry no severity: the general check for aria-owns and the sanity check on where the button role sits.
Related Patterns
- Disclosure: a button that shows and hides a region of content
- Menu Button: a button that opens a menu
- Dialog: a dialog that a button usually opens
- Toggle Button: a button that switches between pressed and not pressed
- Link: navigates to another page, view, or resource instead of performing an action