ARIA (Accessible Rich Internet Applications) communicates roles, states, and properties to assistive technologies—but it doesn’t provide keyboard interaction behavior. Custom components built with ARIA widgets still require manually implemented focus management, keyboard event handling (including Enter, Space, and arrow keys), and dynamic state updates to be keyboard accessible.
Many developers assume that adding ARIA widgets to a custom component makes it keyboard accessible. It doesn’t. ARIA tells assistive technologies what something is—its roles, states, and properties—but says nothing about how it should behave with keyboard input. Focus management, event handling, and state updates all still need to be implemented manually. Without them, custom components that seem accessible in markup can be completely unusable in practice for many people with disabilities.
Key insights
- Ensuring keyboard accessibility is essential to building functional experiences for users of many assistive technologies. Screen readers, voice navigation tools, and switch devices all rely on keyboard events.
- While ARIA widgets are widely used to improve the accessibility of custom components, ARIA communicates semantics, not behavior. Adding ARIA roles and attributes to a custom component does not make it keyboard accessible.
- When ARIA is applied without consideration for keyboard support, it can introduce more accessibility issues that it solves. In fact, pages with ARIA average significantly more accessibility errors than pages without it.
- Voice access tools depend on accessible names and click events—with keyboard operability as a fallback. Dragon Professional ignores ARIA entirely.
- Automated tools only catch a portion of keyboard failures. Manual keyboard and screen reader testing is essential to evaluate the accessibility of custom components.
Keyboard accessibility: A critical gap for ARIA widgets
When accessibility issues arise in custom components, ARIA widgets are often the first tool developers turn to.
The WAI-ARIA specification defines a set of widget roles that describe what a custom control is—a button, menu, or tab, for example—and how it changes over time, even when no native HTML equivalent exists. In that sense, ARIA widgets are designed to bridge the semantic gap between custom interfaces and assistive technologies. But there’s a key aspect of accessibility that ARIA doesn’t handle: keyboard interaction.
This is a critical missing piece. Many people with disabilities rely on keyboards or alternative input devices to engage with the digital world. If any functionality requires a pointing device, the experience is essentially broken for these users. And missing or inconsistent support doesn’t just cause problems for people who navigate with the keyboard only—it also impacts users of screen readers, switch control, and voice access who depend on keyboard events to interact with content.
Because keyboard accessibility is vital to providing usable experiences for people with disabilities, the Web Content Accessibility Guidelines (WCAG) 2.1 Success Criterion 2.1.1 (Keyboard) requires that all functionality be operable through a keyboard interface, with limited exceptions for custom widgets or complex interactions.
The challenges of keyboard support for custom components
Keyboard accessibility is straightforward when you use native HTML elements. Buttons, links, inputs, and form controls come with built-in keyboard behavior, focus management, and activation patterns that work reliably across browsers and assistive technologies. Challenges arise when applications move beyond these basics.
Modern web apps increasingly rely on custom widgets and complex interactions—dropdown menus, autocomplete fields, tab panels, modal dialogs, and interactive data visualizations. These components are typically built from generic elements like div and span, with JavaScript layered on top to manage interaction and state. While this approach enables richer experiences, ensuring keyboard accessibility becomes considerably more complex.
Unlike native controls, custom widgets aren’t focusable by default, don’t respond to standard activation keys, and provide no built-in semantics to assistive technologies. Every aspect of keyboard interaction—focus order, key handling, state changes, and visual feedback—must be implemented explicitly. When any part of that model is incomplete, keyboard users encounter barriers.
Why ARIA widgets don’t solve for keyboard accessibility
ARIA can tell a screen reader that an element is a button. But it can’t make that element focusable, clickable with Enter or Space, or navigable with arrow keys. Those behaviors have to be implemented manually.
As a result, ARIA widgets frequently fail when developers assume that adding ARIA attributes alone will make a component accessible. Without explicit keyboard event handling, logical focus management, and dynamic ARIA state updates, custom widgets remain unusable for many people who rely on assistive technologies.
This gap is reflected in real-world data. The 2026 WebAIM Million Report found that pages using ARIA averaged 59.1 detectable accessibility issues, compared to 42 on pages without it. ARIA only improves accessibility when it’s paired with correct keyboard behavior and consistent state management—especially for complex, interactive components.
ARIA and voice access
Relying on ARIA widgets alone doesn’t just cause problems for keyboard users. It creates barriers for voice navigation users, too. Dragon Professional, for example, has significant limitations with ARIA—a custom button implemented as <a role=”button”> is announced and treated as a link, regardless of its intended behavior. Similarly, Windows Voice Access (which is built into Windows), and Apple Voice Control rely on the accessible name of an element, not its visual label, to interpret voice commands. When those two things don’t match, voice navigation breaks down.
WCAG Success Criterion 2.5.3 (Label in Name) addresses this issue by requiring that an element’s accessible name also contains its visible label text. If you want your custom components to work for voice navigation users, make sure accessible names always include visible label text.
Building keyboard‑accessible web apps: Tips for developers
Now that we’ve established why ARIA alone isn’t enough, let’s explore what it takes to build keyboard-accessible custom components.
When you use ARIA widgets to represent buttons, menus, dialogs, or other controls built from non-semantic elements, you’re also responsible for implementing focus management, keyboard behavior, and state updates yourself. The following best practices can help you improve keyboard accessibility for custom JavaScript-driven components.
Manage focus order and tab sequence explicitly
Keyboard accessibility relies on predictable focus behavior, which native HTML controls provide automatically—but custom components don’t. Native elements such as <button>, <a>, and form inputs are focusable by default and participate correctly in the tab order. Custom widgets built from div or span elements require explicit focus management to be usable with a keyboard.
In custom components, use tabindex=”0″ to make a non-native element focusable without disrupting the natural tab order. And avoid positive tabindex values. They override the document object model (DOM) order and frequently create confusing navigation paths. This is especially true in composite widgets like menus, tab panels, or toolbars, which use a different navigation model altogether—focus lands on the widget, with arrow keys handling navigation within it via roving tabindex or aria-activedescendant.
The overall tab order should follow DOM source order and match the visual layout of the page:
- For custom widgets that dynamically show, hide, or reorder content: This means carefully managing when elements enter or leave the tab sequence.
- For custom controls like page tabs and trees: Use focus management approaches beyond tabindex—such as roving tabindex or aria-activedescendant. These allow the composite control to be one element in the focus navigation order, while providing access to focus child elements via the arrow keys.
Importantly, skip navigation links should remain the first focusable element on the page, even in highly interactive applications. This way, keyboard users can bypass repeated navigation and reach the main content efficiently.
Always provide a visible focus indicator
Every element that can receive keyboard focus must provide a visible focus indicator, including custom controls, composite widgets, and dynamically generated UI elements.
When you build custom components, it’s tempting to remove the browser’s default focus outline for visual reasons. But removing it without a visible replacement violates WCAG Success Criterion 2.4.7 (Focus Visible) and leaves keyboard users with no way to track where they are—particularly problematic in dense, app-like interfaces.
Modern CSS provides :focus-visible, enabling focus indicators to appear during keyboard interaction only. This preserves accessibility without affecting pointer-based design. It’s especially useful for custom components that simulate native controls.
Focus visibility also depends on layout behavior. WCAG 2.2 SC 2.4.11 (Focus Not Obscured) requires that focused elements not be hidden behind sticky headers, modals, or overlays.
Common mitigations include:
- scroll-margin or scroll-padding for focus targets.
- Layout adjustments to ensure focused elements remain visible when content shifts.
Trap focus in modals and use live regions intentionally
Custom dialogs and overlays are among the most common sources of keyboard accessibility failures in modern web apps.
When a modal dialog opens:
- Keyboard focus must move into the dialog.
- Focus must remain trapped inside until the dialog is closed.
- The Escape key should close the dialog.
- Focus must return to the element that triggered the dialog.
Native <dialog> elements and the inert attribute are reliable solutions for managing background content and focus. Without these, users may tab into hidden content, lose focus context, or get trapped.
The same principle applies to live regions: containers that allow assistive technologies to announce dynamic content updates without requiring a focus change. How and when they’re introduced in the DOM matters just as much as how they’re used. They should exist in the DOM on page load for reliable support:
- Use aria-live=”polite” for non-urgent updates.
- Reserve role=”alert” for critical messages only.
Overusing live regions or injecting them dynamically can overwhelm assistive technology users.
Implement full keyboard support on every custom control
Custom controls are where ARIA is most often assumed to solve accessibility, and where keyboard failures happen the most. Controls built from div or span elements aren’t focusable by default, don’t respond to Enter or Space, and don’t expose interaction behavior automatically. A click handler alone doesn’t make a control keyboard accessible.
To make a custom control fully usable:
- Make the element focusable (typically with tabindex=”0″).
- Support activation using both Enter and Space.
- Support a device-independent handler like Click.
- Assign the correct ARIA role.
- Maintain ARIA state attributes dynamically (e.g., aria-expanded, aria-pressed, aria-selected) as interaction occurs.
Miss any of these steps, and a component that seems accessible in a markup review can still be completely unusable for keyboard and assistive technology users.
Common keyboard accessibility failure patterns in custom components
Most keyboard accessibility failures don’t come from native HTML elements. They arise when teams build custom widgets and complex interactions that replace native behavior with JavaScript-driven logic.
Common failure patterns include:
- Click-only event handling: Custom widgets often only respond to click events and don’t support keyboard activation via Enter or Space, leaving keyboard users unable to operate the component.
- Incomplete focus trapping in modals and overlays: Custom dialogs and layered UI frequently fail to trap focus correctly or return focus on close, allowing users to tab into hidden or background content.
- Hidden or removed focus indicators: Custom styling often removes default focus outlines without providing a visible replacement, making it difficult for keyboard users to track their position.
- Focusable elements hidden with ARIA: Applying aria-hidden=”true” or role=”presentation” to elements that remain focusable is a common mistake in custom layouts and dynamic UIs.
- ARIA state attributes that don’t update with interaction: Custom widgets frequently set initial ARIA states but fail to keep them in sync as users interact, causing assistive technologies to report incorrect or stale information.
If you can spot these patterns early in your development process, you’ll prevent regressions and avoid the remediation backlog that builds up when accessibility is treated as an afterthought.
Testing keyboard accessibility
Because keyboard failures in custom components are rarely obvious from markup alone, continual testing is essential to ensure barriers don’t go undetected. Automated accessibility tools catch only a portion of keyboard-related failures, because many keyboard issues stem from missing event handling, broken focus order, or incomplete interaction models rather than static markup errors.
Manual testing is essential. Ideally, it’s performed by an expert, but you can perform a quick spot check by unplugging the mouse and trying to navigate using only the keyboard. Every interactive element should be reachable, clearly focused, and operable. Verify that:
- Modals close with Escape.
- Tab order is logical.
- Focus returns correctly after dialogs close.
- No keyboard traps exist.
For more reliable insight, supplement manual testing with screen reader testing—NVDA with Firefox, JAWS or NVDA with Chrome or Edge, and VoiceOver with Safari.
Keyboard testing reference table
| Interaction | Keystrokes | Notes |
|---|---|---|
| Navigate to interactive elements |
|
Keyboard focus indicators must be present. Navigation order should be logical and intuitive. |
| Link | Enter: activate the link | |
| Button |
|
Ensure elements with role="button" can be activated with both keys. |
| Checkbox | Space: check / uncheck | Users can typically select zero, one, or multiple options. |
| Radio buttons |
|
Users can select only one option from a group. |
| Select (dropdown) menu |
|
Users can often type letters to jump to options. |
| Autocomplete |
|
|
| Dialog | Esc: close | Modal dialogs should trap focus. Non-modals close on blur. Focus should return to trigger on close. |
| Slider |
|
Double sliders use Tab to switch handles. PageUp/PageDown may adjust in larger steps. |
| Menu bar |
|
Menu bars differ from standard link navigation. |
| Tab panel |
|
For dynamic application tabs. Link-style tabs behave differently. |
| Tree |
|
|
| Scroll |
|
Space scrolls only when focus is not on an interactive control. |
Beyond ARIA: Building for accessibility by default
ARIA must be paired with explicit keyboard interaction behavior, focus management, and dynamic state updates to work reliably across assistive technologies. When you treat keyboard support and device independent access as baseline requirements—not afterthoughts—and use ARIA widgets intentionally, you can build digital experiences that work for everyone.
Ready to make keyboard accessibility a consistent, scalable part of your development process? Explore the Accessibility Resolution Playbook to learn how to streamline accessibility across the product development life cycle (PDLC) and get started with our tools for developers.
The post Keyboard Accessibility and Custom Components: Why ARIA Widgets Aren’t Enough appeared first on Level Access.