Skip to content

BbSelectPopover

A searchable picker behind a pill, badge, toolbar control or table cell.

import { BbSelectPopover } from 'bitboss-ui';

On this page

Use it for

Use BbSelectPopover when someone chooses a value from a trigger you design: a status pill, filter chip, avatar stack or table cell. It provides the select engine without drawing a form field.

Use something else when

  • BbSelect: you need a labelled field with guidance and validation
  • BbRadioGroup: a short exclusive choice should remain visible
  • BbDropdown: the rows run commands
  • BbPopover: the panel contains arbitrary content instead of options

Also see: Options and items, Fetching data, Coherence.

Item mapping, item-props, custom rows and option identity follow BbSelect.

Passthrough

Hover or tap a part to outline it. The toggles turn on loading, errors and warnings where the component has them; only parts get a row.

Build a reliable trigger

Spread the activator slot's props onto the focusable element, give it an explicit accessible name and derive its label from application state.

ENG-412

Checkout rounds VAT twice on discounted carts

Assignee

Assign someone before moving this to review.

Do not label the trigger from slot text or selectedOptions: provider-backed options are unresolved until they load, so the trigger can start blank. Reflect shown visually when the panel is open.

The popover has no message area and never joins a BbForm. For an invalid value, render the message next to your trigger and pass its id to aria-describedby; has-errors sets aria-invalid and marks the search field. The pill above does this while nobody is assigned.

Coming from v2

As on BbSelect, clicking the current single value now keeps it selected and closes the panel. Use the slot clear callback for an explicit reset.

Multiple selection

Seed an array when using multiple, then summarize it on the trigger you own.

Filters

max limits the count without locking selected options.

Panel actions and short lists

Use header to name the panel and footer for clear or done actions. Bind the scope's titleId as the title's id: on the phone sheet it names the dialog.

Destination

The panel slots expose clear, close, focus, query and selectedOptions. The clearable prop puts a clear button inside the search field instead, so it does nothing on a list without one.

An array of fewer than six options opens without a search field, unless you listen to option:add; a provider always keeps it. disable-writing drops it on any list, as it does for the six statuses below. Without the field there is no filtering and no option:add.

Status
Coming from v2allowWriting → disableWriting

header and footer replace options:prepend, options:append and their :outer variants. disable-writing replaces and inverts allow-writing, and filter-by accepts string[] or false.

Fetching and dependent pickers

A provider receives one object, { query, reason, modelValue, signal }. Return selected rows on every call whose reason is not 'search' so values remain resolvable.

Ship to

Unlike BbSelect, a seeded model does not force an eager provider call. Keep the trigger independent of loaded options instead of adding prefill: true only to render its label. Provider results pass through the local substring filter unless you set :filter-by="false", as this demo does: its provider matches the query, accents aside, on every call.

Coming from v2

prefill="focus" becomes 'interaction'. prefill: false is search-first; remove it to load on first open. no-data-text and #no-data are empty-text and #empty.

Use dependencies to refetch and enforce-coherence to remove values absent from the refreshed options. Switch the team to Design and the owner filter resets.

Filters

Enforcement validates the seeded model on its first load. Each provider-backed instance therefore makes its own request; an empty response can clear a valid selection.

One picker per table row

Resolve shared options once, pass the same array to every row and keep edits in a draft map keyed by row id.

Orders, with an editable status column
ReferenceTotalStatus
ORD-2026-0496€418.00
ORD-2026-0474€777.90
ORD-2026-0447€458.00
ORD-2026-0417€1,298.00
Edits stay here until you save.

Give each picker its own model. One shared ref lets every instance judge and overwrite the same value; one provider per row makes request count follow row count.

Width, placement and mobile

Set a concrete width for compact triggers; avoid 'auto', which expands against the viewport on this fixed-positioned panel. placement="bottom-start" lines the panel up with the trigger's leading edge.

When props lands on a button inside a wider pill, pass the pill's ref to anchor so the panel lines up with what people see, as the trip destination picker under panel actions does. To open the popover from an element rendered elsewhere, pass that element's ref to activator instead of using the slot.

Below the mobile breakpoint the panel becomes a sheet and placement props stop applying. Style the visible surface with pt:panel, the search field with pt:input and sheet-only corrections with pt:sheet.

Coming from v2flip → disableFlip

Use disable-flip instead of flip. hide-arrow and arrow-padding are removed because this panel has no arrow. Classes: bb-select-popover__search-input is bb-select-popover__input, bb-select-popover__search-clear is bb-select-popover__clear and bb-select-popover-offcanvas is bb-select-popover__sheet.