Starting Point
v0.25.0
Start typing to search...
Go to Page
escClose

Popover

The popover floats a panel next to its trigger for rich content like forms and settings, and closes when the user clicks away. For a simple text hint, reach for the tooltip; for a menu of actions, use the dropdown.

<button id="popover-demo-trigger" class="btn btn-outline">Open popover</button>
 
<div class="popover w-80" data-sp-toggle="#popover-demo-trigger">
  <div class="popover-header">
    <h4 class="popover-title">Dimensions</h4>
    <p class="popover-description">Set the dimensions for the layer.</p>
  </div>
  <div class="grid gap-2">
    <div class="grid grid-cols-3 items-center gap-4">
      <label class="label" for="popover-width">Width</label>
      <input class="input col-span-2 h-8" id="popover-width" value="100%" />
    </div>
    <div class="grid grid-cols-3 items-center gap-4">
      <label class="label" for="popover-max-width">Max. width</label>
      <input
        class="input col-span-2 h-8"
        id="popover-max-width"
        value="300px"
      />
    </div>
    <div class="grid grid-cols-3 items-center gap-4">
      <label class="label" for="popover-height">Height</label>
      <input class="input col-span-2 h-8" id="popover-height" value="25px" />
    </div>
    <div class="grid grid-cols-3 items-center gap-4">
      <label class="label" for="popover-max-height">Max. height</label>
      <input
        class="input col-span-2 h-8"
        id="popover-max-height"
        value="none"
      />
    </div>
  </div>
</div>

Usage

Add the popover class to the panel and point it at its trigger with data-sp-toggle. It opens on click, positions itself relative to the trigger, and closes on an outside click or Escape.

ClassDescription
popoverAdd to the floating panel; carries the data-sp-* options
popover-headerAdd to the block holding the title and description
popover-titleAdd to a heading element
popover-descriptionAdd to a paragraph with supporting text
<!-- This is the trigger -->
<button id="my-trigger" class="btn btn-outline">Open Popover</button>
 
<!-- This is the popover -->
<div class="popover" data-sp-toggle="#my-trigger">Popover content</div>

Examples

Basic

A simple popover with a header, title, and description.

<button id="popover-basic-trigger" class="btn btn-outline">Open Popover</button>
 
<div class="popover" data-sp-toggle="#popover-basic-trigger">
  <div class="popover-header">
    <h4 class="popover-title">Dimensions</h4>
    <p class="popover-description">Set the dimensions for the layer.</p>
  </div>
</div>

Placement

Set where the panel opens relative to its trigger with data-sp-placement. It accepts any Floating UI placement, like top, right, or bottom-end, and the panel flips to the opposite side on its own when there isn't room.

<div class="flex gap-6">
  <button id="popover-start-trigger" class="btn btn-outline btn-sm">
    Start
  </button>
  <button id="popover-center-trigger" class="btn btn-outline btn-sm">
    Center
  </button>
  <button id="popover-end-trigger" class="btn btn-outline btn-sm">End</button>
</div>
 
<div
  class="popover w-40"
  data-sp-toggle="#popover-start-trigger"
  data-sp-placement="bottom-start"
>
  Aligned to start
</div>
<div
  class="popover w-40"
  data-sp-toggle="#popover-center-trigger"
  data-sp-placement="bottom"
>
  Aligned to center
</div>
<div
  class="popover w-40"
  data-sp-toggle="#popover-end-trigger"
  data-sp-placement="bottom-end"
>
  Aligned to end
</div>

With form

A popover holding a compact form, laid out with horizontal fields.

<button id="popover-form-trigger" class="btn btn-outline">Open Popover</button>
 
<div class="popover w-64" data-sp-toggle="#popover-form-trigger">
  <div class="popover-header">
    <h4 class="popover-title">Dimensions</h4>
    <p class="popover-description">Set the dimensions for the layer.</p>
  </div>
  <div class="field-group gap-4">
    <div class="field field-horizontal">
      <label class="label w-1/2" for="popover-form-width">Width</label>
      <input class="input" id="popover-form-width" value="100%" />
    </div>
    <div class="field field-horizontal">
      <label class="label w-1/2" for="popover-form-height">Height</label>
      <input class="input" id="popover-form-height" value="25px" />
    </div>
  </div>
</div>

Hover

Add data-sp-mode="hover" to open on hover instead of click.

<button id="popover-hover-trigger" class="btn btn-outline">Hover me</button>
 
<div
  class="popover"
  data-sp-toggle="#popover-hover-trigger"
  data-sp-mode="hover"
>
  <div class="popover-header">
    <h4 class="popover-title">Quick preview</h4>
    <p class="popover-description">This popover opens on hover.</p>
  </div>
</div>

Options

Popover

Set each option with its own data-sp-* attribute on the popover element.

AttributeValuesDefault
data-sp-toggleCSS selector
data-sp-placementFloating UI placementbottom
data-sp-offsetNumber6
data-sp-modeclick | hoverclick
data-sp-match-widthBooleanfalse
data-sp-staticBooleanfalse
<div
  class="popover"
  data-sp-toggle="#my-trigger"
  data-sp-placement="bottom-start"
></div>

With data-sp-static the popover skips anchored positioning entirely and you position it yourself with utility classes. The toggle wiring, dismissal, and top layer behavior stay. Use it for panels that are viewport-relative instead of trigger-relative, like a full-screen mobile menu:

<div
  class="popover inset-x-0 top-14 bottom-0 h-auto w-auto rounded-none"
  data-sp-toggle="#menu-trigger"
  data-sp-static
>
  ...
</div>

JavaScript

Events

Lifecycle events fire on the popover element; before* events are cancelable.

EventWhen
sp-beforeshowBefore opening (cancelable)
sp-showOpening
sp-shownOpen and settled
sp-beforehideBefore closing (cancelable)
sp-hideClosing
sp-hiddenClosed
el.addEventListener("sp-beforeshow", (e) => {
  if (!ready) e.preventDefault(); // veto the open
});

Methods

Get the instance with sp.popover(el), then call its methods:

MethodDescription
show()Open the popover
hide()Close the popover
toggle()Open if closed, else close
const popover = sp.popover(document.querySelector("#my-popover"));
 
popover.show();