Code example
Common baseline
Keyboard accessible
Must be focusable with Tab and activatable with Enter or Space.
Clear label
Must have text or an aria-label that describes the button's purpose.
Focus indicator
A visible focus ring must appear when the button receives keyboard focus.
Color contrast 4.5:1
Text and background must meet a minimum contrast ratio of 4.5:1.
Communicate disabled state
Use aria-disabled or the disabled attribute to indicate an inactive state.
Loading state announcement
Provide aria-busy="true" and a screen-reader-friendly loading message.
Icon button label
Buttons with only an icon must have an aria-label.
44×44px touch target
Ensure a minimum 44×44px touch target on mobile.
Do not implement buttons with div/span
<div onClick> has no keyboard accessibility. Use <button> instead.
Do not distinguish state with color alone
Do not rely solely on color to indicate active/inactive state.
Design system implementations
Additional checks
Handle aria-busy for loading state
Add aria-busy="true" to a loading button and apply aria-hidden to the CircularProgress so screen readers do not announce the spinner.
Verify contrast for outlined variant
The border color of the outlined variant must meet a minimum 3:1 contrast ratio against the background. Verify this in the default theme.
Check role when using component="a"
Using the component prop to render an <a> makes it a link, not a button. Keep component="button" for actions; use <a> only for navigation.
Code sample
Implementation notes
- –MUI Button renders a <button type="button"> element by default.
- –The disabled prop removes focus from the tab order. Use aria-disabled only if you need to keep focus on the element.
- –Avoid component="a" for non-navigation actions — it changes the semantic meaning from button to link.
- –Use sx={{ minHeight: 44 }} to meet the WCAG 2.5.5 touch target size requirement.