Tooltip and popover implementations: opening, dismissal and clipping

Dataset Last tested 24 October 2026

Choose a tooltip or popover by how people open it, move onto its content and dismiss it. This ledger compares twenty configured implementations across focus, hover, persistence, Escape, overflow, emulated touch and a no-JavaScript path.

Choose the kind of interaction first

The ledger contains sixteen software integrations and four related native browser patterns. The native rows are auto and manual popovers, an anchored popover and a modal dialog. They share browser capabilities rather than representing four independent products. A dialog also has a different interaction contract from a tooltip; its row makes that distinction visible.

The original five entries—Floating UI, Tippy, Radix, React Aria and Bootstrap—remain. Their documentation records are kept beside the executed configurations; Tippy’s v6 property reference is one of those records.1 All twenty rows represent loaded examples. The order carries no score or recommendation.

NameVersionFocusHoverPersistenceEscape/focusUnclippedTouchNo JS
Floating UI React0.27.20YYYYYY*N
Tippy.js6.3.7YYYNYY*N
Radix Tooltip1.4.1YYYYYN*N
React Aria Components1.22.1YYYYYN*N
Bootstrap Tooltip5.3.8YYNNYY*N
Shoelace Tooltip2.20.1YYYYpartialY*N
Spectrum Web Components Tooltip1.12.5YYYYYN*N
Vaadin Tooltip25.3.4YYYYYN*N
UIkit Tooltip3.25.27YYNYYY*N
Materialize Tooltip1.0.0YYNNYY*N
Bulma Tooltip3.0.2YYNNNY*Y
Microtip0.2.2YYNNNY*Y
Hint.css3.0.0NYNNNY*Y
Balloon.css1.2.0YYNNNY*Y
Ark UI Tooltip5.39.3YYYYYN*N
Ariakit Tooltip0.4.42YYYYYN*N
Native auto popoverBrowser-native; original E1 fixture 1NNYYYY*Y
Native manual popoverBrowser-native; original E1 fixture 1NNYNYpartial*Y
Native anchored auto popoverBrowser-native; original E1 fixture 1YYYYYN*Y
Native modal dialogBrowser-native; original E1 fixture 1NNYpartialYpartial*N

Y = observed; N = observed contradiction; partial = qualified; – = not tested; * = emulated.

Start with the opening contract

Floating UI’s React recipe assembles positioning and interaction hooks.2 Radix provides composed trigger and content components; Bootstrap’s tooltip is an opt-in plugin.34 Those are different implementation units. The configuration field records what the fixture author supplied, including triggers, portals, delays and persistence rules.

A tooltip should provide a short explanation associated with its trigger. Content containing controls or requiring deliberate opening needs a different contract. The Popover API supplies a browser mechanism for placing content above the surrounding page; a dialog provides a modal or non-modal interaction surface.56 Neither name alone determines the opening behaviour of a particular implementation.

React Aria’s tooltip documentation describes a deliberate boundary around touchscreen interaction and points toward alternatives.7 Treat that documented contract separately from the emulated-touch result in its configured row. A vendor’s documentation and a browser observation answer different questions, even when they agree.

Follow the awkward cases across the row

The pointer leaves the trigger and enters the content. Read focus and hover together, then follow the persistence field. Opening is only the first part of that path. Persistence describes whether the content remains available during that movement; it does not imply that interactive controls belong inside a tooltip.

Escape closes the content. Check focus as well as visibility: the field combines dismissal with focus retention. Closing an overlay and returning focus to a different element is a different outcome from closing it while focus stays on its trigger. The note identifies the before-and-after elements rather than treating every closed overlay as the same result.

The trigger sits inside a clipped container. Read the overflow field independently of opening and dismissal. The relevant field concerns a fixture inside a clipped container. A portal or top-layer implementation can differ from an element positioned inside that container; the saved configuration identifies the rendering approach. Placement and clipping should remain separate concerns when you adapt an example.

Filter, then reproduce

Use the demo to search names and select an exact observation label. It displays original comparison records without loading the packages or sending a search request. An empty result means no row matches the filter. Reset restores the complete inventory and the search field.

Y, N, partial and – retain their distinct meanings: observed behaviour, an observed contradiction, a qualified result and no established result. Emulated-touch values carry *. An unknown is not an absent feature, and a documented option is not automatically a default or an observed outcome.

Download the CSV or JSON for full notes. METHOD.md identifies the pinned files, licences, hashes, original fixtures and repeatable steps. The tested package files are kept in a separate test harness and are not republished here.

Work through the pointer-and-focus example for a small original interaction contract. Use the overflow comparison to examine local positioning, portals, the top layer and anchors. Their examples support implementation decisions without substituting their outcomes for a vendor row.

Our observation data is licensed under CC BY 4.0. The tested packages retain their own licences.

Not covered on this page

Sources

  1. Tippy.js: All Props. v6.x documentation, displaying 6.3.7 in the initial record; accessed 24 October 2026. ↩

  2. Floating UI: Tooltip. Living React recipe; accessed 24 October 2026. ↩

  3. Radix Primitives: Tooltip. Initial documentation record displayed component version 1.3.0; accessed 24 October 2026. ↩

  4. Bootstrap: Tooltips. 5.3 documentation channel; accessed 24 October 2026. ↩

  5. MDN: Popover API. Browser API reference; accessed 24 October 2026. ↩

  6. MDN: dialog. Element reference; accessed 24 October 2026. ↩

  7. React Aria: Tooltip. Living documentation; accessed 24 October 2026. ↩

How we test: methodology. Found a mistake? Corrections.