Popover API — Why You Can Now Build Tooltips Without JavaScript
A single popover attribute handles open/close, Esc dismissal, and accessibility automatically
<button popovertarget="tip-1">Hover me</button>
<div id="tip-1" popover="auto" role="tooltip">
This is a native tooltip
</div>
Zero lines of JavaScript. No event listeners. No state tracking. Yet it dismisses with Esc, supports keyboard navigation, and screen readers announce it correctly.
How Traditional Tooltips Break
"Show on hover, hide on leave" sounds simple. Deploy it and problems pile up.
Keyboard users Tab to the trigger — nothing appears. Screen readers read it twice or not at all. Fast mouse movement causes flickering. Small screens cause overlap. Esc doesn't dismiss. Focus gets lost.
Event listeners accumulate. Separate hover/focus handling. Outside-click edge cases. Manual ARIA synchronization. The code bloats. Not because the implementation is bad, but because the web platform had no concept of "this element is a tooltip."
What Popover API Changed
Add the popover attribute and the browser understands the element's role. Three things work automatically.
1. Open/close without JavaScript
popovertarget="id" connects button to popover. Done. Browser handles click and focus interactions. popovertargetaction specifies behavior — show, hide, or toggle (default).
2. Automatic Esc handling
No global keydown handler. No Esc-specific cleanup logic. The browser recognizes popovers as dismissible elements.
3. Automatic ARIA sync
aria-expanded updates automatically with popover open/close. No manual management. No stale state risk. Lighthouse stops warning about incorrect ARIA — there are no custom ARIA states to get wrong.
auto vs manual
auto closes on outside click, Esc, or when another auto popover opens. Good for tooltips.
manual requires explicit dismissal. Focus restoration isn't automatic either — you must return focus to the trigger manually on blur. Good for toast notifications.
Where JavaScript Is Still Needed
Timing control. Native popovers open/close instantly. Fast mouse movement still causes flicker. Delay between hover and open requires JavaScript.
Hover intent. The browser can't know why a pointer is over an element — intentional hover or passing through. JavaScript handles this.
But the core shifted. JavaScript no longer owns the entire interaction model. Popover API handles base open/close; JavaScript just layers intent detection on top.
When Libraries Still Win
Complex positioning with nested scroll containers and custom flipping logic — Floating UI still wins here. CSS anchor positioning is emerging but early-stage.
Large design systems needing centralized behavior and guardrails across teams.
For most cases though — simple tooltips, dropdown menus, toast notifications — Popover API is enough. No library needed.
Key Points
popover + popovertarget handles open/close, Esc, keyboard navigation automatically
Automatic aria-expanded sync eliminates an entire category of accessibility bugs
auto closes on outside click/Esc, manual requires explicit control — choose by use case
Timing control and hover intent still need JavaScript, but the core interaction model is browser-owned