Skip to content

BbDropdownButton

A button with primary action and all other actions collected in a dropdown.

import { BbDropdownButton } from 'bitboss-ui';

On this page

Props

NameDescription
activeClass Type: string

Class to apply when the link is active.

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.

Forwarded to the menu: unset follows the global adaptive config, so on a phone the menu is a bottom sheet. Pin it false only for a desktop-only dense tool.

See example
append:icon Type: string

Icon to be added on the right of the text.

ariaCurrentValue Type: "page" | "step" | "location" | "date" | "time" | "true" | "false"Default'page'

Value passed to the attribute aria-current when the link is exact active.

async Type: booleanDefaultfalse

Inertia: runs the visit without blocking — the page stays interactive and several async visits can be in flight at once.

block Type: booleanDefaultfalse

Displays the component as full width.

The extra width goes to the main button; the toggle keeps its own. Useful in a narrow column, not as a way to make the two halves match.

See example
cacheFor Type: string | number | (string | number)[]

Inertia: how long a prefetched response stays fresh before it is re-fetched. A single duration, or [staleAfter, expiresAfter]. Typed platform-agnostically (matching BbButton) so the library's types never require @inertiajs/vue3 to be installed.

cacheTags Type: string | string[]

Inertia: tags to file this visit's prefetch cache under, so a later request can invalidate the whole tagged group.

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.

Menu rows only (28px → 24px on the flyout, 44px → 36px on the sheet); the split button’s own height comes from size. Pair it with size="sm" in a dense toolbar.

See example
component Type: string

Inertia: the page component this visit resolves to. Rarely set by hand — the server normally decides it.

data Type: object

Request payload forwarded to Inertia when navigating via href in an Inertia-enabled app. Ignored when not using Inertia.

disableAutoLoading Type: booleanDefaultfalse

Disables the automatic loading state that tracks async actions (enabled by default). Only affects the main action button: the split toggle half still mirrors the dropdown's internal async-action loading state.

Opts the main button out of tracking its own async onClick; the toggle keeps reflecting menu-action state either way. Replaces v2 autoLoading with the polarity inverted, so a leftover :auto-loading="false" does nothing and nothing warns.

See example
disabled Type: booleanDefaultfalse

Disables both halves: the main button and the menu toggle.

Freezes both halves at once. v2 disabledWhileLoading is gone: a busy half is always disabled now, which is what stops a second click racing the pending action.

download Type: string | boolean

Marks an href link as a download: renders a plain <a download> doing a native navigation (never an Inertia/router visit), so file downloads work. Pass a string for the suggested filename. A native-anchor signal alongside target and external.

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.

exactActiveClass Type: string

Class to apply when the link is exact active.

except Type: string[]

Inertia: the inverse of only — properties to EXCLUDE from a partial reload. Pass one or the other, not both.

external Type: booleanDefaultfalse

Forces an href link to render as a plain <a> (native navigation), bypassing Inertia/router interception — same intent as Nuxt's external. A native-anchor signal alongside target and download.

form Type: string

The id of the BbForm the main button submits from outside it (the native form attribute), with type="submit".

headers Type: object

Additional HTTP headers forwarded to Inertia when navigating via href in an Inertia-enabled app.

href Type: string

Returns the hyperlink's URL. Can be set, to change the URL.

icon Type: string

Used when only an icon with no text should be displayed.

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.

instant Type: booleanDefaultfalse

Inertia: navigate optimistically on click and reconcile when the response lands, instead of waiting for the round trip.

interactiveWhileLoading Type: booleanDefaultfalse

Keeps the button clickable while it is loading. Buttons are disabled while loading by default; this escape hatch exists for toggles that must stay interactive (e.g. the dropdown-button caret).

items Type: BbDropdownItem[]

The menu: every entry is a row (BbDropdown's item model, groups and submenus included). The main action is the component itself (its default slot, @click, href / to, type), never an item. Unset or empty with no #dropdown slot: no toggle, a plain button.

Only the menu: every entry is a row, with BbDropdown’s item model (groups and submenus included). The main action is the component itself: its default slot, @click, href / to, type. Before beta.58 items[0] was the main button; bitboss-ui check flags a split button with no label.

See example
loading Type: booleanDefaultfalse

Triggers a loading indicator. A loading button is soft-disabled on its own (aria-disabled, out of the tab order, clicks and navigation blocked) and keeps its variant colours; with disabled set too, loading still wins the look.

Drives the main button by hand, for work the component cannot see. It does not touch the toggle.

See example
method Type: "get" | "post" | "put" | "patch" | "delete"

HTTP method used for Inertia navigation when href is provided in an Inertia-enabled app. Ignored otherwise.

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.

Reaches the phone sheet only, e.g. a title. A pt inside it styles that sheet alone and merges after pt:header / pt:footer.

See example
offset Type: numberDefault4

Space the floating container will maintain from the activator.

onBefore Type: (() => void)

Lifecycle hook invoked by Inertia right before the request is sent.

onCancel Type: (() => void)

Lifecycle hook invoked by Inertia when a request is cancelled.

onCancelToken Type: ((cancelToken: unknown) => void)

Receives the Inertia cancel token source when a request is initiated. Can be used to cancel the request. Typed platform-agnostically (matching BbButton) so the library's types never require @inertiajs/vue3 to be installed.

onError Type: ((errors: Record<string, string>) => void)

Inertia's hook for a VALIDATION error answer (the 422 path): the only failure callback Link accepts. onHttpException (5xx) and onNetworkError are router.visit() / useForm() options, never Link props.

onFinish Type: (() => void)

Lifecycle hook invoked by Inertia after the request has finished (regardless of success or error).

only Type: string[]

Limits the properties that are preserved in Inertia partial reloads.

onPrefetched Type: (() => void)

Lifecycle hook invoked by Inertia when a prefetch for this link has completed and is cached.

onPrefetching Type: (() => void)

Lifecycle hook invoked by Inertia when a prefetch for this link starts.

onProgress Type: ((progress: { percentage: number | undefined; }) => void)

Progress callback invoked by Inertia with the upload/download percentage when available.

onStart Type: (() => void)

Lifecycle hook invoked by Inertia when a request starts.

onSuccess Type: (() => void)

Lifecycle hook invoked by Inertia when a request succeeds.

padding Type: numberDefault10

Minimum empty space to keep from the edge of the page

pageProps Type: Record<string, unknown> | ((currentProps: Record<string, unknown>, sharedProps: Record<string, unknown>) => Record<string, unknown>) | null

Inertia: props to merge into the next page optimistically, before the server responds. Either an object or a function of the current props. Typed platform-agnostically (matching BbButton) so the library's types never require @inertiajs/vue3 to be installed.

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.)

Resolved against the whole split control, not the toggle that opened the menu — so the default bottom centres the panel under the pair. trigger is not exposed: the toggle always opens on click.

See example
prefetch Type: string | boolean | string[]

Inertia: fetch and cache this link's page ahead of the click. true uses the default trigger; a string or list of strings picks them ('mount', 'hover', 'click').

prepend:icon Type: string

Icon to be added on the left of the text.

Dresses the main button, as on BbButton. A menu row takes its own prepend:icon in items.

See example
preserveScroll Type: boolean | ((props: Record<string, unknown>) => boolean)Defaultfalse

Controls whether Inertia should preserve the current scroll position after navigation. Can be a boolean or a predicate receiving the visit props.

preserveState Type: boolean | ((props: Record<string, unknown>) => boolean) | nullDefaultfalse

Controls whether Inertia should preserve the current state after navigation. Can be a boolean or a predicate receiving the visit props.

preserveUrl Type: booleanDefaultfalse

Inertia: keep the current URL in the address bar even though the page content changes.

pt Type: BbDropdownButtonPtMap

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, BbDropdownButtonPtState, "default" | "destructive">) => PtItemResult)

Passthrough, attribute form: one attribute per part, pt:<part>, and per part and state, pt:<part>:<state>. Parts: footer, header, icon, input, item, itemDescription, itemIcon, itemText, main, panel, root, sheet, spinner, text, toggle. States: activeLink, default, destructive, disabled, exactActiveLink, ghost, link, loading, open, outline, primary, secondary, selected.

main and toggle are the two halves, each handed to its button as that button’s pt:root: pt:main="rounded-l-full" plus pt:toggle="rounded-r-full" is a pill split button with a square seam. input styles every searchable group’s search field in the menu.

See example
queryStringArrayFormat Type: "brackets" | "indices"Default'brackets'

Format to use when serializing array values into the query string for Inertia requests.

replace Type: booleanDefaultfalse

Calls router.replace instead of router.push.

size Type: Responsive<Sizes>Default"md"

Sets the size of the button. When the value is a string, it will be applied to all screen sizes. Otherwise, it will be applied to the screen size specified by the object.

Shared by both halves, and takes the responsive map form ({ sm: "sm", lg: "md" }). One size for the pair, so the halves never disagree.

See example
tag Type: ButtonTagDefault'button'

Element to render for the plain (non-link, non-router) button: 'button' (default), 'div'/'span' when nesting inside another button or link, or 'label' for a file-upload trigger. Ignored when href/to make the button render as a link.

target Type: string

Sets or retrieves the window or frame at which to target content.

text Type: string

Text content of the component.

to Type: string | wt | bt

Route Location the link should navigate to when clicked on.

toggle:icon Type: string

Replaces the chevron shown inside the dropdown toggle button. A constrained alternative to a slot: only the toggle's icon changes, so the button keeps its semantics. Named after the part it sits in (the toggle), the way prepend:icon / append:icon name theirs.

Swaps the toggle’s chevron and nothing else — an overflow "…" for a dense row. Deliberately a prop rather than a slot: there is no activator slot, because the toggle is part of the contract.

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.

type Type: "button" | "submit" | "reset"

Gets the classification and default behavior of the button.

variant Type: ButtonVariantTypeDefault"primary"

Visual variant shared by both buttons of the split control. 'none' takes no look (you own hover, focus and disabled); register a real one with the plugin's buttonVariants and style .bb-button--<name>.

Shared by both halves, from BbButton’s ladder — a name registered through buttonVariants works here too. Replaces v2 theme. One variant for the pair; a menu row’s own variant (destructive) styles only that row.

See example
viewTransition Type: booleanDefaultfalse

Inertia: run the page swap inside a View Transition, where the browser supports one.

width Type: string | numberDefault'auto'

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

A percentage resolves against the split control’s width, still floored at the menu’s 128px minimum. anchor is not exposed here because it is hard-wired to that control.

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

A row of a selectable group was selected — the menu's own event, re-emitted with the same payload (the item's resolved value).

Re-emitted from the menu with the same payload, the row’s value. Bind the group’s v-model for the state; listen here for the moment of a change.

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

A row of a selectable group was unselected (same payload as above).

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.

<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.

<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.

<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.

<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.

<value>:prepend Type: BbDropdownItemSlotProps

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

append:icon Type: BbButtonIconSlotProps

The main button's trailing icon, replacing append:icon.

default Type: any

The main button's label (falls back to text).

dropdown Type: any

Menu companions, forwarded into the dropdown: a <BbDropdownGroup> binding a group of items by id. A #dropdown slot keeps the toggle even with no items.

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. Forwarded to the underlying BbDropdown.

header Type: BbDropdownButtonEdgeSlotProps

Content pinned to the top of the dropdown panel, outside the scroll area.

Forwarded into the inner dropdown unchanged, along with footer, the edge slots and per-row slots. Every slot except the label (default), #dropdown and activator goes there.

See example
icon Type: BbButtonIconSlotProps

The main button's icon, replacing the icon prop; inside its icon part (pt:icon, --icon-size, the loading spinner), with its states.

item:append Type: BbDropdownButtonItemSlotProps

The trailing region of every menu row, replacing its append:icon; the submenu chevron and the check on a selected row take its place (BbDropdown's rules).

See example
item:prepend Type: BbDropdownButtonItemSlotProps

The leading region of every menu row, replacing its prepend:icon (BbDropdown's rules).

Replaces every menu row’s prepend:icon; per-group and per-row slots beat it, as on BbDropdown. It never reaches the main button: dress that with prepend:icon.

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. Forwarded to the underlying BbDropdown.

prepend:icon Type: BbButtonIconSlotProps

The main button's leading icon, replacing prepend:icon.

Renamed and removed

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

  • arrowPaddingremovedfails silently
  • autoLoadingdisableAutoLoadingfails 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.

  • slotno-dataemptyfails silently
  • right:icontoggle:iconfails silently
  • themevariantfails silently