On this page
Popover
Contextual bubbles with the Popover API
(popover="auto") and CSS Anchor Positioning. The
browser handles stacking, light-dismiss, and placement — no Popover
plugin and no Popper.
| What runs it | JavaScript | |
|---|---|---|
| Bootstrap 5.3 | Popover plugin, which includes Tooltip and Popper | 15.5 KB gzip |
| This repo | Popover API and CSS Anchor Positioning. No Popper. | 0 KB |
When that API is missing,
this page also loads invoker-commands.js (0.8 KB gzip).
See Polyfills.
| Avoid |
|
|---|
How it works
-
command="toggle-popover"andcommandforreplacedata-bs-toggle="popover". There is no initialize-with-JS step. -
Title and body live in the markup as
.popover-headerand.popover-body, not indata-bs-title/data-bs-content. -
The bubble is
.popoverwithpopover="auto". The browser puts it in the top layer and closes it on outside click or Escape. -
CSS Anchor Positioning tethers the bubble to the trigger that opened
it (the popover invoker). Add
.bs-popover-top,.bs-popover-end,.bs-popover-bottom, or.bs-popover-startinstead ofdata-bs-placement. Default placement is right, matching Bootstrap. - Keep the trigger and the popover as siblings so the invoker relationship is obvious in the markup.
-
commandworks on<button>, not<a href>. -
Only one
popover="auto"bubble is open at a time. -
Top-layer popovers are not clipped by overflow, so
container: 'body'is not needed. Put the popover markup inside a modal if it must participate in that dialog’s focus.
Live demo
Titles and body content are real HTML in .popover-header and .popover-body. Click the button to toggle.
Popover title
<span class="d-inline-block">
<button type="button" class="btn btn-lg btn-danger" command="toggle-popover" commandfor="popoverLive">
Click to toggle popover
</button>
<div class="popover bs-popover-end" popover="auto" id="popoverLive">
<div class="popover-arrow"></div>
<h3 class="popover-header">Popover title</h3>
<div class="popover-body">And here’s some amazing content. It’s very engaging. Right?</div>
</div>
</span> Four directions
Four options are available: top, right, bottom, and left. Directions are mirrored when using Bootstrap in RTL. Add .bs-popover-top, .bs-popover-end, .bs-popover-bottom, or .bs-popover-start.
fallbackPlacements / auto-reorient would move
the arrow to a new side. Without JavaScript the
.bs-popover-* arrow stays on the class you set, so
pick an explicit placement instead of auto.
<div class="d-flex flex-wrap justify-content-center gap-2">
<span class="d-inline-block">
<button type="button" class="btn btn-secondary" command="toggle-popover" commandfor="popoverTop">
Popover on top
</button>
<div class="popover bs-popover-top" popover="auto" id="popoverTop">
<div class="popover-arrow"></div>
<div class="popover-body">Top popover</div>
</div>
</span>
<span class="d-inline-block">
<button type="button" class="btn btn-secondary" command="toggle-popover" commandfor="popoverEnd">
Popover on right
</button>
<div class="popover bs-popover-end" popover="auto" id="popoverEnd">
<div class="popover-arrow"></div>
<div class="popover-body">Right popover</div>
</div>
</span>
<span class="d-inline-block">
<button type="button" class="btn btn-secondary" command="toggle-popover" commandfor="popoverBottom">
Popover on bottom
</button>
<div class="popover bs-popover-bottom" popover="auto" id="popoverBottom">
<div class="popover-arrow"></div>
<div class="popover-body">Bottom popover</div>
</div>
</span>
<span class="d-inline-block">
<button type="button" class="btn btn-secondary" command="toggle-popover" commandfor="popoverStart">
Popover on left
</button>
<div class="popover bs-popover-start" popover="auto" id="popoverStart">
<div class="popover-arrow"></div>
<div class="popover-body">Left popover</div>
</div>
</span>
</div> Custom popovers
Customize appearance with CSS variables on a class on the .popover element (Bootstrap’s data-bs-custom-class injected that class from JS).
Custom popover
<span class="d-inline-block">
<button type="button" class="btn btn-secondary" command="toggle-popover" commandfor="popoverCustom">
Custom popover
</button>
<div class="popover bs-popover-end custom-popover" popover="auto" id="popoverCustom">
<div class="popover-arrow"></div>
<h3 class="popover-header">Custom popover</h3>
<div class="popover-body">This popover is themed via CSS variables.</div>
</div>
</span> Dismiss on next click
popover="auto" already light-dismisses on the next click outside the bubble (and on Escape).
data-bs-trigger="focus" requires an
<a tabindex="0"> and JavaScript.
Native light-dismiss is the same user-visible behavior on a
<button>. Hover and focus-only triggers are not
available without script.
Dismissible popover
<span class="d-inline-block">
<button type="button" class="btn btn-lg btn-danger" command="toggle-popover" commandfor="popoverDismiss">
Dismissible popover
</button>
<div class="popover bs-popover-end" popover="auto" id="popoverDismiss">
<div class="popover-arrow"></div>
<h3 class="popover-header">Dismissible popover</h3>
<div class="popover-body">And here’s some amazing content. It’s very engaging. Right?</div>
</div>
</span> Disabled elements
A disabled control cannot be a command invoker. Wrap a .btn.disabled span in a button that toggles the popover.
<span tabindex="0">. Invoker Commands
require a <button>, so the wrapper is a
transparent button around a visually disabled
.btn.disabled. Hover/focus as the only trigger is not
native.
<span class="d-inline-block">
<button type="button" class="border-0 bg-transparent p-0" command="toggle-popover" commandfor="popoverDisabled">
<span class="btn btn-primary disabled">Disabled button</span>
</button>
<div class="popover bs-popover-end" popover="auto" id="popoverDisabled">
<div class="popover-arrow"></div>
<div class="popover-body">Disabled popover</div>
</div>
</span> Accessibility
The bubble is a popover, not a dialog. Escape and a click outside close it. Invoker Commands keep aria-expanded in sync on the trigger.
Put real heading text in .popover-header. Do not rely on data-bs-title.
Browser support
| No script | Polyfill | No fallback |
|---|---|---|
popover="auto": Chrome 114+, Firefox 125+, Safari 17+. | command on the trigger, the same polyfill as the modal. | CSS Anchor Positioning: Chrome 125+, Safari 26+, Firefox 147+. Without it the bubble is not attached to the trigger. .bs-popover-auto does not reorient; it matches .bs-popover-end. |