Tooltip Benchmark

Bootstrap 5 Tooltip JS (Popper.js + TemplateFactory + Sanitizer) vs Native Popover API

Bootstrap JS

Uses bootstrap.Tooltip + Popper.js — creates DOM elements, runs createPopper() for positioning, sanitizes HTML via TemplateFactory + Sanitizer on every show.

Native Browser API

Uses Popover API (popover="manual") — element already in DOM, browser handles top-layer stacking. Show/hide via showPopover() / hidePopover(). Zero JS positioning needed.

Native Popover tooltip
Initializing... 0%

Results

Metric Bootstrap Tooltip Native Popover API
Initialization time (200 instances) - -
Toggle time (10 cycles × 200 items) - -
Instance memory cost (200 instances) - -
JS code size - -
CSS output size
_tooltip.scss (4.2 KB)
- -
Bootstrap JS 200 items — data-bs-toggle="tooltip"
Native Browser API 200 items — popover="manual"
About tooltip creation: Bootstrap Tooltip calls Popper.js’s createPopper() on every show, creates a new tooltip <div> via TemplateFactory, sanitizes its HTML content via Sanitizer, and runs JavaScript to calculate offsets and apply inline transform styles. Native Popover API tooltips are already in the DOMshowPopover() simply moves them to the top layer. Zero DOM creation, zero JS positioning, zero sanitization.
Native popover tooltip — entire implementation
HTML
<!-- Trigger -->
<button style="anchor-name: --my-tip-trigger;">
  Hover me
</button>

<!-- Tooltip (Bootstrap utility classes for styling) -->
<div popover="manual" id="my-tip"
     class="px-2 py-1 bg-dark text-white rounded small border-0 shadow"
     style="position-anchor: --my-tip-trigger;">
  Tooltip text
</div>
CSS (only positioning — no styling needed)
[popover].native-tooltip {
  inset: unset;                   /* reset UA default */
  position: fixed;
  bottom: anchor(top);            /* place above trigger */
  left: anchor(center);
  translate: -50% -4px;           /* center horizontally + gap */
}
JS (only hover listeners)
btn.addEventListener('mouseenter', () => tip.showPopover());
btn.addEventListener('mouseleave', () => tip.hidePopover());