Skip to content

BbDropdown

Displays contextual action menus and menu content (includes the co-located BbDropdownGroup export, which is how a selectable group is bound).

import { BbDropdown } from 'bitboss-ui';

On this page

Props

NameDescription
activator Type: Record<string, any> | HTMLElement | null

An external activator element or component ref: the activator slot is not rendered, and the listeners and ARIA (aria-haspopup / aria-expanded / aria-controls) are attached to it; don't add your own.

The no-wrapper alternative to the activator slot, for when you already hold an element or component ref. It gets the same aria-haspopup / aria-expanded / aria-controls attached programmatically — so do not hand-write those on the referenced element either.

See example
adaptive Type: booleanDefaultconfig.adaptive (true)

On mobile (below config.mobileMaxWidth), renders the menu as a bottom sheet that drills into submenus one level at a time instead of hover flyouts; slots and selection are unchanged. Unset: the global config.adaptive.

Unset resolves to the global adaptive config, which is true: on a small viewport the menu is a bottom sheet, not a flyout. Pin it false for a desktop-only dense tool, or for a test that asserts against one surface.

See example
anchor Type: Record<string, any> | HTMLElement | nullDefaultthe activator element

The element the panel positions against when it should differ from the activator (a wrapper the activator is part of); an HTMLElement or component ref. It also drives a percentage width. Ignored with placement="cursor".

Positions the panel against something other than the trigger — the case being a control whose trigger is only part of it, like the toggle half of a split button. A percentage width then resolves against the anchor too. Ignored when placement is cursor.

See example
boundary Type: string | Record<string, any> | HTMLElement | null

Keeps the panel inside this element alongside its trigger (sideways for a menu above or below); away from the trigger it may pass the edge, and only the viewport flips it. An HTMLElement, a component ref or a CSS selector: a useTemplateRef, never $refs.x (not reactive).

closeOnSelect Type: booleanDefaultunset (close after a single-choice change)

Whether a selection closes the menu. Unset: a change in a single-choice group closes it (an untick too, at any depth); a multiple group stays open. true: every selection change closes it. false: none does.

compact Type: booleanDefaultfalse

Compact density, the BbSelect ladder: flyout rows 28px → 24px, sheet rows 44px → 36px (a sheet row stays a touch target). The label size does not change.

See example
disabled Type: booleanDefaultfalse

Disables the component

Freezes the whole component, trigger included. It is not the same as disabling every item: a disabled item is skipped by keyboard navigation while the menu still opens.

eager Type: booleanDefaultfalse

Renders the menu panel at mount instead of on the first open (the phone sheet's too), and keeps its rows after a close. Without it the rows mount on each open and go once the menu has closed.

emptyText Type: string

Default placeholder text shown when a pipeline group resolves to no items. A group's own emptyText overrides this; both fall back to the localized common.emptyText ('No data to display').

The empty-result counterpart of loadingText, with the same per-group override and the same locale fallback.

See example
enforceCoherence Type: booleanDefaultfalse

Default for pipeline groups: drop selections that are no longer present in a group's current items (e.g. after a dependencies re-fetch) from the selection and v-model. A group's own enforceCoherence overrides this.

The dropdown-level default for pipeline groups, overridable per group. It stays lazy: a group nobody opened never fetches and never prunes, and pruning never runs against an empty or still-loading item set.

failedText Type: string

Default placeholder text shown when a pipeline group's latest load FAILED (its items getter threw). A group's own failedText overrides this; both fall back to the localized common.failedText ("Couldn't load items").

id Type: string

Names this dropdown: the activator's id (unless it already has one), the menu's menu_<id>, and the key useBbDropdownContext(id) and a companion BbDropdownGroup pair by. Generated when omitted.

Name the dropdown when something outside it reads its state: useBbDropdownContext(id) returns each selectable group with its picks, read-only.

See example
items requiredType: BbDropdownItem[]Default[]

The menu rows, each a BbBaseButton (button, a or router-link): a flat array for one group, nested arrays for divider-separated groups, or InternalGroup objects for titled / selectable sections. A row's own items opens a submenu.

Three shapes, mixable: an item, a nested array (a divider-separated section), or a group object. label is what a row says and a group's heading; a row is identified by value and a group by id (rows were { key, text } in v2 and early v3 betas). value is optional on a plain action or link row; a selectable row and a row with its own slot need one, and a selectable or bound group needs an id.

See example
loadingText Type: string

Default placeholder text shown while a pipeline group's async items load. A group's own loadingText overrides this; both fall back to the localized common.loadingText ('Loading...').

Pipeline groups only, and the default for all of them; a group can override it with its own loadingText. Unset, it is the plugin locale’s "Loading…" string.

See example
offCanvasProps Type: Partial<BbOffCanvasProps>

Props for the phone sheet (the BbOffCanvas that adaptive renders on mobile), spread over its defaults. A pt inside it styles only the sheet (passthrough guide § Inside the sheet). The sheet hides its ✕; { hideClose: false } brings it back.

Merged over the sheet’s own side: "bottom", size: "auto", draggable: true. Ignored entirely when adaptive resolves to false, so it is not a way to configure the desktop panel.

See example
offset Type: numberDefault4

Space the floating container will maintain from the activator.

padding Type: numberDefault10

Minimum empty space to keep from the edge of the page

placement Type: Placement | "cursor"Default"bottom"

Position of the dropdown relative to the activator. Use 'cursor' to anchor at the mouse/touch coordinates. (No arrow is drawn either way — arrows are tooltip-only in v3.)

Every floating placement, plus cursor — which anchors the panel at the pointer and is what you pair with trigger: "contextMenu" for an OS-style menu. The panel flips on its own when there is no room.

See example
pt Type: PtItemMap<BbDropdownPtPart, BbDropdownItemPtPart, BbDropdownPtState, InternalItem, "default" | "destructive">

Passthrough, object form: the same keys as the pt:* attributes without the prefix. See the pt:<part> row.

pt:<part> Type: PtValue | ((ctx: PtItemCtx<InternalItem, BbDropdownPtState, "default" | "destructive">) => PtItemResult)

Passthrough, attribute form: one attribute per part, pt:<part>, and per part and state, pt:<part>:<state>. Parts: footer, header, input, item, itemDescription, itemIcon, itemText, list, panel, root, sheet. States: activeLink, default, destructive, disabled, exactActiveLink, open, selected.

See example
queryDebounceTime Type: numberDefault300

Debounce (ms) applied to the async re-fetch a searchable group fires as the user types. Applies to every searchable group in the menu.

Applies to a searchable group’s own search field, debouncing the query before it reaches that group’s async getter. Nothing else on the component reads it.

See example
transitionDuration Type: numberDefault150

How long the transition has to last in milliseconds. Menus use the fast transition (150) rather than the medium one (250) the other popovers default to: a menu is opened to pick one command and is gone again, so it answers faster than a panel the user reads or edits in.

trigger Type: DropdownTrigger | DropdownTrigger[]Default"click"

Interaction(s) that open the dropdown. Accepts a single trigger or an array to combine them. - 'click' — left-click / tap (default) - 'contextMenu' — right-click on desktop, long-press on mobile

Takes an array to combine them (["click", "contextMenu"]). On touch devices the contextMenu gesture is a long press, and right-clicking again while open moves the menu rather than closing it.

See example
width Type: string | numberDefault"auto"

Width of the dropdown in pixels, percentage, or 'auto' to fit content.

Content-sized by default with a 128px floor — not a fixed width. Pass a number when menus have to line up across the rows of a table, and a percentage when the panel should match its trigger.

See example

Events

NameDescription
hidden Type: (): void

Emitted once the menu has finished closing.

hide Type: (): void

Emitted as soon as the menu starts to close.

item:selected Type: (value: any): void

The user selected a row in a selectable group, at the click — also when a controlled companion's app then refuses the value. The payload is the row's value (its item-value for pipeline groups, else its value) — symmetric with BbTable's item:selected.

Fires for any selectable group with the changed item’s value — its itemValue in a pipeline group, otherwise its value. Bind the companion’s v-model when you want the state; use this when you want the moment.

See example
item:unselected Type: (value: any): void

The user unselected a row (a multiple toggle, a clearable re-click, a chip ×, or the old value a single pick replaces). Payload is the item's resolved value, matching item:selected.

Fires when a row of a multiple group is unticked, or when the picked row of a clearable single group is clicked again. A plain single group is a radio group: re-clicking its pick changes nothing, so neither event fires (the row’s onClick still runs).

See example
show Type: (): void

Emitted as soon as the menu (the popover, or the sheet on a phone) starts to open.

shown Type: (): void

Emitted once the menu is open and its open transition has finished.

Slots

The listed properties are the ones exposed to the slot scope.

NameDescription
<groupId> Type: BbDropdownItemSlotProps

That group's title line (the group is passed as item, groupTitle is true).

<groupId>:append Type: BbDropdownItemSlotProps

The trailing region of that group's title line.

<groupId>:item Type: BbDropdownItemSlotProps

The content of every row of that group, and no other; a row's own #<value> still wins.

See example
<groupId>:item:append Type: BbDropdownItemSlotProps

The trailing region of every row of that group; replaces their append:icon. The check takes its place on the selected row.

See example
<groupId>:item:prepend Type: BbDropdownItemSlotProps

The leading region of every row of that group — e.g. an avatar per record, drawn from item.meta, while other rows keep their prepend:icon.

The switcher slot: draw each record (an avatar, a logo) from item.meta on this group’s rows while every other row keeps its prepend:icon. Set meta on each item, or through itemProps in a fetched group.

See example
<groupId>:prepend Type: BbDropdownItemSlotProps

The leading region of that group's title line.

<value> Type: BbDropdownItemSlotProps

One row's content (label and description), by its value; in a fetched group, by its resolved itemValue.

Named after the row’s value in kebab-case: billingInfo, billing_info and Billing info are all #billing-info. For a value with accents or punctuation, write #[slotKey(value)] (slotKey is exported from bitboss-ui) rather than spelling it by hand.

See example
<value>:append Type: BbDropdownItemSlotProps

One row's trailing region; replaces its append:icon and its submenu chevron. The check takes its place on the selected row.

The only slot that can replace a row’s submenu chevron. On the selected row of a selectable group the check still wins.

See example
<value>:prepend Type: BbDropdownItemSlotProps

One row's leading region; replaces its prepend:icon.

See example
activator Type: BbDropdownActivatorSlotProps

The element that triggers the dropdown to open. Spread props onto your trigger element.

Spread its props onto a real focusable element or the menu has nothing to attach ARIA and keyboard handling to. The scope also carries loading, true while any item’s async onClick is still running — this replaces the exposed loading a v2 template ref read.

See example
default Type: any

Hosts <BbDropdownGroup> companions. They register their group with the dropdown and render nothing themselves.

empty Type: BbDropdownPlaceholderSlotProps

Replaces the default "no data" placeholder row shown in a pipeline group that resolved to no items. Rendered once per empty group.

header Type: BbDropdownEdgeSlotProps

Content pinned to the top of the dropdown panel, outside the scroll area. Stays visible while the items scroll and is separated from them by a divider — for a title or a filter field.

Pinned above the scrolling items and separated by a divider — a title, or a field that filters the list you build. On the adaptive sheet it becomes the sheet’s pinned header.

item:append Type: BbDropdownItemSlotProps

The trailing region of every row (and group title line), replacing its append:icon. A named slot wins over it; the submenu chevron and the check on a selected row take its place.

Replaces the rows’ append:icon. It never replaces a submenu chevron, the check takes its place on the selected row, and a group’s or a row’s own named slot beats it.

See example
item:prepend Type: BbDropdownItemSlotProps

The leading region of every row (and group title line), replacing its prepend:icon. A row's own or its group's named slot wins over it.

Rendered before every row’s content, group titles included — there groupTitle is true and item is the group. It replaces the rows’ prepend:icon, and a group’s or a row’s own named slot beats it. The payload is read-only: keep slot content presentational and leave clicks to the dropdown.

See example
loading Type: BbDropdownPlaceholderSlotProps

Replaces the default loading placeholder row shown in a pipeline group while its async items load. Rendered once per loading group.

Renamed and removed

Names from v2 and from earlier 3.0 betas that no longer work, and what to write instead.

  • arrowPaddingremovedfails silently
  • item fielditems[].keyitems[].valuefails silently

    A row's identity: its v-model value (any type, compared by hash) and its #<value> slots; check --fix renames it.

  • item fielditems[].textitems[].labelfails silently

    A row's text; check --fix renames it.

  • item fielditems[group].keyitems[group].idfails silently

    A group's identity, the same word as <BbDropdownGroup id>; check --fix renames it.

  • methodloadingremovedfails silently

    Read loading from the activator slot scope (#activator="{ loading }") instead of a template ref.

  • slotno-dataemptyfails silently
  • noDataTextemptyTextfails silently