Focus Hover Parity
Critical - WCAG Level A
What the issue is:
This problem occurs when interactive behaviors are triggered only by mouse hover events (mouseenter/mouseover or CSS :hover) and are not available when the same element receives keyboard focus. Typical examples: menus, dropdowns, tooltips, or popovers that appear on hover but do not appear when the trigger receives focus or when activated via keyboard.
Why it matters:
Keyboard-only users (including many screen reader and motor-impaired users) cannot produce mouse hover events. If a control reveals important content only on hover, keyboard users will not be able to reach or activate that content, violating WCAG 2.1.1 Keyboard and causing lost functionality and confusion.
How to fix it:
Ensure every interactive behavior that appears on hover is also available when the trigger receives keyboard focus and can be controlled with standard keyboard actions. Practical steps:
Use semantic, focusable controls for triggers: button or link instead of plain div/span. Add tabindex only when necessary.
Expose state with ARIA: use aria-expanded on the trigger and aria-controls to reference the controlled element. Set aria-hidden="true"/"false" on the popover/menu if you hide/show via CSS or JS.
Support keyboard activation: listen for Enter and Space to toggle, and Escape to close. Also support focusin/focusout or focus/blur to reveal on focus if the desired behavior is focus-to-open.
Use CSS :focus-within or :focus to mirror :hover styles for visible changes so keyboard users get the same visual cues.
Ensure content within revealed panels is reachable by tabbing and that focus order is logical.
Best practices:
Prefer explicit activation (click/press toggles menu) over implicit focus-only show/hide for complex menus
Always keep a visible focus indicator
Consider using role="menu" only when implementing keyboard menu behaviors fully
Test with keyboard only and with a screen reader.
Common mistakes:
Binding only mouseenter/mouseleave handlers
Leaving triggers non-focusable (no tabindex or not a native button/link)
Toggling visibility visually but not updating aria-hidden/aria-expanded; relying solely on CSS :hover without providing :focus or :focus-within equivalents.