Skip to content

BbPopover

A floating panel anchored to a trigger, for content the reader moves into and acts on.

import { BbPopover } from 'bitboss-ui';

On this page

Use it for

Reach for BbPopover when a trigger should open a small panel the user then works in: quick settings, a filter, a notifications list, an inline detail card. Fields, switches, links and buttons all belong inside it.

Use something else when

  • BbTooltip: the reader only needs a sentence about the control in front of them
  • BbDropdown: the panel is only a list of actions
  • BbDialog: the task owns the page until it is resolved
  • BbOffCanvas: it is supplementary side content, docked to an edge rather than to a control

Pass Through

Hover or tap a part to outline it. Toggles flip loading, errors and warnings when the component has them — only parts highlight.

A tooltip describes, a popover contains. If the reader has to move into the content and do something there, stay here.

Edit in place

Put your trigger in the activator slot and spread its props onto it.

That one spread is the whole contract: it carries the anchor, the element id, the ARIA attributes and the open handler. Miss it and you get a button that looks right and does nothing.

Q3 revenue review

width takes pixels, or a percentage of the trigger's width. Only the percentage form re-measures when the trigger resizes; leave width off and the panel sizes to its content.

Closing the panel

The panel renders no close button of its own. The affordance is yours, and the default slot hands you close.

Call close after the write, not before. A handler that dismisses first and commits second is one early return away from losing the edit silently.

Escape and a click outside dismiss the panel too, and for a read-only panel that is enough. A panel holding a form needs a visible way out as well, Cancel beside Save, because nothing on screen says Escape is safe. The header and footer slots receive close on the same scope.

Coming from v2

show-close and close-label are gone.

Focus

A popover is modal. It opens as a native <dialog>, so Tab stays inside the panel and the page behind it cannot be used while it is open.

25 of 25

Design around that: a click outside lands on the panel's own transparent backdrop, dismisses the popover, and does not reach the control underneath. Anyone wanting to press something behind the panel presses it twice.

Opening moves focus to the first focusable element; closing returns it to the trigger. When that first element is not the one the reader came for, point focus-target at the right one with a CSS selector.

The panel paints in the top layer, so it is never clipped by an overflow: hidden ancestor and never needs a z-index.

Coming from v2

The restore-focus prop is gone. Restoring focus is behaviour now, not a knob.

Placement and geometry

placement puts the panel on a side of the trigger: the top, right, bottom and left families, each with -start and -end alignment.

It defaults to bottom, and it flips itself near a viewport edge. Pick what reads best in the common case rather than guarding against the exception.

Three props tune the rest:

  • offset: the gap from the trigger (3)
  • padding: the gap the panel keeps from the page edge (10)
  • boundary: the region the panel must not escape, usually a sidebar or a scrolling container

The panel stays tethered to its trigger: scroll the trigger out of view and the popover closes.

Coming from v2

A popover no longer draws an arrow, so hide-arrow and arrow-padding are gone. If you passed :hide-arrow="false" in v2 to get a bubble with a point on it, that shape is a BbTooltip now.

Header, footer and long content

scrollable caps the panel at the height still available and scrolls the body inside it.

The header and footer slots sit outside that scroll region, each with its own padding and divider. A title stays put and footer actions stay reachable without a sticky workaround.

Use it for feeds and long lists. Leave it off for atomic content: a calendar that scrolls internally is a worse calendar.

Triggers and cursor anchoring

trigger chooses the gesture: click by default, contextMenu for right-click and long-press, or an array to accept both.

Tagged: accessibility

Pair contextMenu with placement="cursor" and the panel anchors where the pointer was rather than on the element.

Keep the distinction: a plain list of actions is BbDropdown. A context popover earns its place when the surface holds controls the user operates in place.

Driving it from outside

v-model opens and closes the popover: write true to open and false to close. It writes the model back on every dismiss, so reading it stays accurate.

Panel is closed.

activator is for a trigger that already exists somewhere else, like a toolbar button or a table cell. Pass the element or the component ref and the popover attaches the listeners and the ARIA itself. There is no props to spread, and the activator slot is not rendered.

Coming from v2

popoverRef.value.show(), .close() and .isOpen are gone, replaced by v-model. In an untyped template the leftover call is undefined at runtime rather than a compile error, which makes it the quietest break on this component.

The mobile sheet

Below 768px a popover opens as a bottom-anchored, draggable BbOffCanvas sheet instead of a floating panel.

That is the shipped behaviour, and the header, default and footer slots carry over unchanged. Pass :adaptive="false" to keep the floating panel at every width.

The part that catches people: width is ignored in sheet mode. A sheet sizes itself. Tune it with off-canvas-props, which merges over the defaults side: 'bottom', size: 'auto', draggable: true.

The surface is decided when the panel opens and frozen until it closes, so resizing the window never swaps a live panel into a sheet.

Styling the floating and sheet surfaces

The panel takes its paint from the theme tokens and gives you three class hooks.

css
.bb-popover .bb-popover__header {
    padding: 12px;
    font-weight: 600;
}

.bb-popover .bb-popover__content {
    padding: 12px;
}

.bb-popover .bb-popover__footer {
    background-color: var(--bb-muted);
}

Every BbPopover in the project carries those hooks, so put your own class on the popover and scope the rules to it rather than restyling .bb-popover globally.

Those hooks and your class live on the floating panel only. Below 768px the popover is a BbOffCanvas sheet that neither reaches: a class on the popover lands on an invisible positioning wrapper the sheet does not have, though a data-* attribute still gets there. When a look has to hold on a phone, set it through pt. pt:panel is the bordered box on desktop and the sheet itself on a phone, and pt:header, pt:content and pt:footer follow the bands into the sheet.

Keep the look off pt:root. Padding, a border or a background there does not style the box, it draws a frame around it, and a click on that frame counts as outside and closes the popover. Desktop geometry on pt:panelrounded-md, w-64, px-1 — reshapes the sheet too: correct it for the phone with pt:sheet, which wins there. And keep overflow-hidden off a panel that can become a sheet, or a gap shows under it while it is dragged.

Coming from v2

theme is gone. Colour comes from --bb-panel, --bb-border, --bb-radius and --bb-shadow.