1.4.13 Content on Hover or Focus
When additional content appears on hover or focus, it is dismissible, hoverable, and persistent until the user removes hover/focus or the content is no longer relevant.
What This Rule Means
WCAG 1.4.13 applies to any additional content that becomes visible when a user hovers over a trigger element with a pointer or moves keyboard focus to it. Common examples include tooltips, dropdown menus, popovers, and custom title attributes. The criterion defines three requirements for such content:
- Dismissible — The user can close the additional content without moving the pointer or focus, typically by pressing Escape. This is essential because the content may obscure other page elements the user needs to read.
- Hoverable — The user can move the pointer from the trigger to the additional content without it disappearing. This is critical for magnification users who may need to move the viewport to read the tooltip content.
- Persistent — The content remains visible until the user actively dismisses it, moves hover/focus away, or the information is no longer valid. It must not disappear on a timer.
Exceptions exist when the browser controls the appearance (native title tooltips) and when the additional content communicates an input error that does not obscure other content.
Why It Matters
Screen magnification users often trigger hover content while scanning the page. If a tooltip appears but disappears when they try to move their magnified viewport to read it, the content is inaccessible. The "hoverable" requirement ensures these users can reach and read the content.
The "dismissible" requirement protects users from popup content that blocks the view of what they were trying to read. Without Escape key support, a tooltip may cover critical content with no way to remove it without moving the mouse — which might trigger another tooltip.
The "persistent" requirement prevents timed tooltips that vanish before a user has finished reading them, which is problematic for users who read slowly or use magnification.
Related axe-core Rules
There are no automated axe-core rules for 1.4.13. The three behavioral requirements (dismissible, hoverable, persistent) require interactive testing that automated tools cannot perform. This is a manual testing criterion.
How to Test
- Identify all hover/focus-triggered content: tooltips, popovers, dropdown menus, submenus, info bubbles.
- For each, hover over the trigger to make the content appear.
- Test Dismissible: Press Escape while the content is visible. It should disappear without moving the pointer.
- Test Hoverable: Move the pointer from the trigger element onto the additional content. It must remain visible while hovered.
- Test Persistent: Leave the pointer on the trigger and wait. The content should not disappear on a timer.
- Test with keyboard: Tab to the trigger element. The additional content should appear. Tab away — it should disappear.
- Test with screen magnification (200-400%) to verify the hoverable content can be reached while magnified.
How to Fix
Build tooltips and popovers that meet all three requirements:
<div class="tooltip-wrapper">
<button
aria-describedby="tip-1"
class="tooltip-trigger"
>
More info
</button>
<div
id="tip-1"
role="tooltip"
class="tooltip-content"
>
This action cannot be undone. All data will be permanently deleted.
</div>
</div>
/* CSS for hoverable, persistent tooltip */
.tooltip-content {
display: none;
position: absolute;
z-index: 10;
background: #1a1a2e;
color: #ffffff;
padding: 0.75rem 1rem;
border-radius: 4px;
max-width: 300px;
/* Pointer gap bridge — prevents dismiss when moving to tooltip */
margin-top: -2px;
}
/* Show on hover of wrapper (covers both trigger and content) */
.tooltip-wrapper:hover .tooltip-content,
.tooltip-wrapper:focus-within .tooltip-content {
display: block;
}
/* Keep tooltip visible when hovering the tooltip itself */
.tooltip-content:hover {
display: block;
}
// JavaScript for Escape dismissal
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
const visibleTooltips = document.querySelectorAll(
'.tooltip-content[style*="display: block"], .tooltip-content:hover'
);
visibleTooltips.forEach(tip => {
tip.style.display = 'none';
});
// Also close any open popovers
const openPopovers = document.querySelectorAll(
'[data-popover-open="true"]'
);
openPopovers.forEach(popover => {
popover.setAttribute('data-popover-open', 'false');
});
}
});
For dropdown menus, use the wrapper-based hover approach to maintain the hoverable path:
<nav>
<ul class="menü">
<li class="menü-item has-submenu">
<a href="/services" aria-expanded="false" aria-haspopup="true">
Services
</a>
<ul class="submenu" role="menü">
<li role="menuitem"><a href="/services/audit">Audit</a></li>
<li role="menuitem"><a href="/services/remediation">Remediation</a></li>
</ul>
</li>
</ul>
</nav>
/* Submenu hover pattern — hoverable by design */
.submenu {
display: none;
position: absolute;
top: 100%;
left: 0;
min-width: 200px;
background: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* Wrapper hover keeps submenu open when moving to it */
.has-submenu:hover .submenu,
.has-submenu:focus-within .submenu {
display: block;
}
Common Mistakes
- Tooltips that disappear when the user moves the pointer from the trigger to the tooltip content (gap between elements).
- No Escape key handler — the tooltip cannot be dismissed without moving the pointer or focus.
- Tooltips on a timer that disappear after 3-5 seconds regardless of user interaction.
- CSS-only tooltips using :hover on the trigger element alone, making the tooltip content non-hoverable.
- Custom title attributes implemented as tooltips but not meeting the three behavioral requirements.
- Popovers that cover important content with no way to dismiss them via keyboard.