Why keyboard access matters
Many people—blind users, those with low vision or motor limitations, and anyone using assistive technology—navigate sites with a keyboard or switch device instead of a mouse. If a control can’t be reached, identified, or activated from the keyboard, the task is effectively blocked. That includes menus, accordions, filters, product variants, sliders, date pickers, carousels, and “Place Order” buttons. Accessibility isn’t achieved when the page looks good; it’s achieved when the full user journey is operable.
How keyboard navigation works
By default, browsers create a tab order from focusable elements (links, buttons, inputs, selects, textareas). Users move through this order with Tab and Shift+Tab, activate with Enter or Space, and use arrow keys for certain widgets (radio groups, menus, tabs). The currently focused element must be obvious visually. Developers shape this experience with semantics (native HTML), tabindex (used sparingly), focus management for overlays, and CSS for visible focus.
Top failure patterns (and how to fix them)
1) Invisible or removed focus indicators
A shocking number of sites hide the focus outline for aesthetics (outline: none;) and never replace it. Without a visible focus state, users can’t tell where they are.
/* Bad: removes focus indicator */
:focus { outline: none; }
/* Better: use :focus-visible for keyboard focus and provide a strong style */
:focus-visible {
outline: 3px solid #1a73e8;
outline-offset: 2px;
border-radius: 4px;
}
2) Broken tab order
Reordering content visually with CSS grid/flex without matching DOM order creates confusing focus jumps. Overusing tabindex (especially values > 0) also causes chaos.
Keep DOM order aligned with visual order; reserve tabindex="-1" for programmatic focus targets and avoid positive tabindex altogether.
3) Menus and mega-menus that trap or lose focus
Hover-only menus and off-canvas navs often open without focus, drop it into the page behind the overlay, or fail to return focus when closed. Users need: focus sent into the menu on open, roving tabindex or arrow key navigation within, Esc to close, and focus returned to the trigger on close.
// Example: open menu then send focus
openMenuBtn.addEventListener('click', () => {
menu.hidden = false;
firstMenuItem.focus(); // menu must be in the tab order
});
// Example: close on Esc and restore focus
menu.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
menu.hidden = true;
openMenuBtn.focus();
}
});
4) Dialogs/modals without focus management
Proper dialogs receive focus on open, trap focus inside (no tabbing to the page behind), and return focus to the opener on close. The title should be announced as a dialog heading. CSS-only overlays rarely meet these requirements; wire them explicitly.
// Minimal trap strategy (conceptual)
const focusables = () => dialog.querySelectorAll('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
dialog.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
const nodes = [...focusables()];
const first = nodes[0], last = nodes[nodes.length - 1];
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
});
5) Custom controls built from <div> without semantics
A styled div looks like a control but isn’t one. Prefer native elements (<button>, <input>, <select>).
If custom is required, implement the full pattern: role, accessible name, state, and keyboard handlers for Enter/Space/Esc, with arrow keys where expected.
6) Sliders, carousels, and date pickers that can’t be operated
Provide keyboard support: arrow keys to adjust sliders, Tab into the control and Enter/Space to toggle play/pause for carousels, and predictable arrow/grid navigation for calendars. Don’t auto-advance content without a pause/stop button in the tab order.
7) Skip links missing or hidden
“Skip to content” is a simple link placed at the top of the page that moves focus past repeating navigation. It should be the first tabbable element and visible on focus.
<a class="skip-link" href="#main">Skip to main content</a>
<main id="main">...</main>
/* Reveal only when focused */
.skip-link {
position: absolute; left: -9999px; top: 0;
}
.skip-link:focus-visible {
left: 12px; top: 12px; padding: 8px 12px; background: #fff; border: 2px solid #1a73e8; border-radius: 6px;
}
8) Forms without labels or clear errors
Each input needs a programmatic label; placeholders are not labels. On validation, send focus to the first error and ensure errors are announced and associated with their fields. Keyboard users must be able to reach help icons and tooltips as well.
A 10-minute keyboard audit (any site)
- Turn off your mouse. Use only Tab, Shift+Tab, Enter, Space, arrows, and Esc.
- Find the focus. Is the focus indicator always visible, never obscured by sticky headers or off-screen?
- Use the skip link. Can you skip nav to the main heading?
- Test the main menu. Open/close from the keyboard; move with arrows; press Esc to close; confirm focus returns to the trigger.
- Open a modal. Does focus land inside and trap? Can you close with Esc and return to the trigger?
- Operate a carousel/slider. Can you pause/play and move slides with keys?
- Complete a form. Are labels announced? After submit with errors, does focus land on the first error with specifics?
- Change pages or views. In single-page apps, does focus move to a logical heading when content updates?
- Check custom widgets. Tabs, accordions, date pickers—do arrows and Enter/Space work as expected?
- Final action. Can you reach and activate the primary call-to-action (e.g., “Place Order”) without a mouse?
Design-system patterns that prevent regressions
- Buttons: use real
<button>; never a div. Include visible focus styles and keyboard activation. - Links:
<a href>for navigation; avoid click handlers on non-links. Maintain an obvious visited state for orientation. - Tabs: arrow keys switch tabs, Tab moves into the panel. Keep
aria-selectedaccurate and use roving tabindex for tablist. - Accordions: Enter/Space toggles; arrow keys move between headers. Ensure the expanded panel is next in the DOM for reading order.
- Menus: arrow navigation within; Esc closes; focus returns to the trigger. Prevent off-screen tabbing.
- Dialogs: focus to first focusable on open, trap inside, return focus on close. Disable page scroll while open.
- Carousels: include pause/previous/next controls in the tab order; no auto-rotation without a pause button.
- Forms: persistent labels, clear error associations, logical next-field order, and accessible help.
Code snippets you can reuse
<!-- Semantic primary action -->
<button type="submit" class="btn-primary">Place order</button>
<!-- Roving tabindex for tablist (conceptual) -->
const tabs = Array.from(document.querySelectorAll('[role="tab"]'));
let index = 0;
tabs.forEach((t, i) => {
t.tabIndex = i === index ? 0 : -1;
t.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight') index = (index + 1) % tabs.length;
if (e.key === 'ArrowLeft') index = (index - 1 + tabs.length) % tabs.length;
tabs.forEach((tab, j) => { tab.tabIndex = j === index ? 0 : -1; });
tabs[index].focus();
});
});
Common pitfalls that block tasks
- Positive tabindex values: They override natural order and create confusion. Use DOM order instead.
- Focus hidden behind sticky UI: Ensure focused elements aren’t covered by fixed headers or chat widgets.
- Hover-only reveals: Keyboard users can’t “hover.” Ensure menus/tooltips are also toggled by focus/keys.
- Focus loss on updates: SPA content changes must move focus to a logical heading or container.
- Keyboard traps: Don’t trap inside components (except dialogs). Ensure users can Tab forward/back across the page.
Documentation to capture when harm occurs
If a missing or broken keyboard path blocks you from a service, keep a clear record:
- Screenshot or short recording showing the last focused element and failed key action.
- Exact keys pressed (e.g., “Tab from email field; focus disappeared, could not reach Submit”).
- Date/time, URL, device/browser, and any assistive tech in use.
- Consequence (missed deadline, inability to book/pay, abandoned cart, lost discount).
Accessibility is good usability
Clear focus styles help power users blaze through tasks. Logical tab order matches expectations on mobile hardware keyboards. Keyboard operability aligns with performance and semantics: real buttons, real links, real forms. These improvements reduce support tickets, increase completion rates, and make UI state changes predictable for all users.
How The Brensilber Law Firm helps (briefly)
When keyboard barriers deny equal access to services, our role is to turn your experience into action. We focus on meticulous documentation, clear articulation of harm, and outcomes that drive meaningful fixes—so the next visitor doesn’t hit the same dead end. If you encountered the issues described here, contact us to discuss options or visit our Resource Hub for more guides.