Buttons are one of the most fundamental interactive elements on the web. When implemented correctly, they provide clear, predictable interactions for all users. This guide covers essential accessibility practices for button implementation.

Why Button Accessibility Matters

Buttons are used for actions like submitting forms, opening dialogs, and triggering functionality. When buttons aren’t accessible, users with disabilities may not be able to complete these essential tasks. Proper button implementation ensures that:

  • Screen readers can announce button purposes
  • Keyboard users can activate buttons
  • Users with motor impairments can see clear focus indicators
  • All users understand what the button will do

Basic Accessible Button

The foundation of accessible buttons starts with semantic HTML:

<button type="button" class="btn btn-primary">
  Click me
</button>

Key Points:

  • Use the <button> element for actual buttons
  • Specify the type attribute to prevent form submission
  • Provide clear, descriptive text content

Button with Icon

When buttons contain only icons, you must provide an accessible name:

<button type="button" class="btn btn-icon" aria-label="Close dialog">
  <svg aria-hidden="true" focusable="false" width="16" height="16">
    <path d="M4 4l8 8m0-8l-8 8"/>
  </svg>
</button>

Accessibility Features:

  • aria-label provides the button’s purpose to screen readers
  • aria-hidden="true" hides the icon from screen readers
  • focusable="false" prevents the SVG from receiving focus

Submit and Reset Buttons

For form buttons, use appropriate types:

<form>
  <input type="text" name="email" />
  <button type="submit">Send Email</button>
  <button type="reset">Clear Form</button>
</form>

Button with Loading State

For buttons that trigger async actions, provide feedback:

<button type="button" class="btn" aria-busy="true" aria-live="polite">
  <span class="spinner" aria-hidden="true"></span>
  Processing...
</button>

CSS for Accessible Buttons

Proper styling ensures buttons are visually accessible:

.btn {
  padding: 0.5rem 1rem;
  border: 2px solid transparent;
  border-radius: 4px;
  cursor: pointer;
  font-size: 1rem;
  transition: all 0.2s ease;
  min-height: 44px; /* Minimum touch target size */
}

/* Focus indicator - never remove this! */
.btn:focus {
  outline: 2px solid #007bff;
  outline-offset: 2px;
}

.btn:hover {
  background-color: #0056b3;
}

/* Disabled state */
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* Loading state */
.btn[aria-busy="true"] {
  position: relative;
  color: transparent;
}

.btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border: 2px solid transparent;
  border-top: 2px solid currentColor;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

Common Accessibility Mistakes

❌ Bad: Using div as button

<div class="btn" onclick="handleClick()">
  Click me
</div>

Problems:

  • Not keyboard accessible
  • Screen readers won’t announce it as a button
  • No semantic meaning

❌ Bad: Missing accessible name

<button type="button">
  <svg><!-- icon only --></svg>
</button>

Problems:

  • Screen readers can’t determine the button’s purpose
  • Users don’t know what the button does

❌ Bad: Removing focus outline

.btn:focus {
  outline: none; /* Never do this! */
}

Problems:

  • Keyboard users can’t see which element has focus
  • Violates WCAG 2.1.1 (Keyboard) and 2.4.7 (Focus Visible)

Testing Your Buttons

  1. Keyboard Navigation: Tab to each button and press Enter/Space
  2. Screen Reader: Use NVDA, JAWS, or VoiceOver to navigate
  3. Focus Indicators: Ensure focus is clearly visible
  4. Touch Targets: Verify buttons are at least 44x44px on mobile
  5. Color Contrast: Ensure text meets WCAG contrast requirements

Advanced Patterns

Toggle Button

<button type="button" aria-pressed="false" aria-label="Toggle notifications">
  <svg aria-hidden="true">
    <!-- bell icon -->
  </svg>
</button>
<button type="button" aria-expanded="false" aria-haspopup="true" aria-label="Open menu">
  Menu
  <svg aria-hidden="true">
    <!-- dropdown arrow -->
  </svg>
</button>

Remember: The key to accessible buttons is using semantic HTML, providing clear accessible names, ensuring keyboard accessibility, and maintaining visible focus indicators.