Props
| Name | Description |
|---|---|
adaptive Type: booleanDefaultconfig.adaptive (true) | When Set it per instance only to disagree with the app-wide |
append:icon Type: stringDefaultthe chevron-down glyph | Name of the icon to be added at the end of the input. Replaces the chevron rather than sitting next to it. v3 removed both the |
autocomplete Type: string | Guides to the browser as to the type of information expected in the field. |
autofocus Type: Booleanish | Focuses the field when it mounts (a dialog already open included), unless the user is typing in another field. |
clearable Type: booleanDefaultfalse | Displays a clear button when the input has a value and is being interacted with. |
comma Type: booleanDefaultfalse | Sets the display model for selected values to a list of comma separated string. In this mode the user cannot deselect an option by pressing the close button. A display mode, and it costs the per-value close button: in |
compact Type: booleanDefaultfalse | Compact density: the field uses the |
dependencies Type: unknown[] | Defines an array of dependencies that will trigger actions in the component upon change. Compared by value hash, not by reference, so an array rebuilt on every render does not refetch. Coherence is lazy: a select with a provider and an empty model ignores changes here until its first load. See example |
depsDebounceTime Type: numberDefault0 | Timeout used to debounce response to changes to dependencies. Raise it when the upstream field changes on every keystroke. See example |
description Type: string | Text between the label and the input. Unlike the hint it is always visible; it joins the input's |
disabled Type: booleanDefaultfalse | Disables the component. |
disableWriting Type: boolean | "auto" | "mobile" | "desktop"Default'auto' | Hides the panel's search field: Unset, the search field hides itself on an array of fewer than six options (the plugin's |
emptyText Type: string | String displayed when there are no items to display. The line the panel shows when nothing matches. Use the |
enforceCoherence Type: booleanDefaultfalse | After every successful load that is not a search, removes the picks the fetched rows do not contain (a single model resets to Reach for it when |
errors Type: string | string[] | Error messages under the field, a string or array, in an |
failedText Type: stringDefaultthe localized common.failedText ("Couldn't load items") | String displayed in the empty state while the latest load FAILED (the provider threw): the twin of |
filterBy Type: false | string[]Default[] | What typing filters on: empty = the display text and description; item paths = those fields ( Replaces the match against the display text rather than adding to it, and every listed path must exist on every item or matching throws. With a provider it still applies, on top of the response: a server match whose text does not contain the query is hidden by this local pass. |
formless Type: booleanDefaultfalse | Keep this control out of the enclosing For a control that is not form data, such as a filter that sits inside a |
groupBy Type: string | ((item: T) => string | number | symbol) | Path to item property for grouping options. Grouping changes how the list virtualises: a flat list windows per row, a grouped list windows per group, so one group with thousands of options mounts in full. Keep such lists flat, or chunk them. See example |
hasErrors Type: booleanDefaultfalse | Define if the component should be in an error state. It usually attaches a CSS class for styling purposes. |
hasWarnings Type: booleanDefaultfalse | Define if the component should be in a warning state. Same chrome as errors with |
headerHeight Type: number | Height of group headers in the listbox (px). Defaults to 32px (24px compact; 36px / 32px on mobile viewports). Only applies when Set it in the prop and not in CSS: the number also feeds the virtualiser, so a stylesheet override desynchronises the paint from the scroll maths. See example |
hideLabel Type: booleanDefaultfalse | Visually hides the label of the input while maintaining accessibility. |
hint Type: string | Text box to be displayed near the input, usually to indicate instructions. |
id Type: string | The |
inputAlign Type: FieldCrossAlign | Vertical position of the control in a side-by-side row; not |
itemHeight Type: numberDefault28 | Height of the options in the listbox (px). Defaults to 28px (24px compact; 44px / 36px on mobile viewports). An explicit value wins on every viewport. Raise it to match taller |
itemProps Type: BbSelectItemProps<T> | ADDITIONAL row fields, never the text or value: Only extra fields: |
items requiredType: T[] | ((context: BbSelectItemsContext) => T[] | Promise<T[]>) | The options: an array, or a provider called with a Pass your domain objects as they are and describe them with |
itemText Type: ItemAccessor<T, string>Defaultown label, else text, else JSON.stringify(item) | Defines a path that returns a property of the object to use as text or a function that returns a string.
Unset: own |
itemValue Type: ItemAccessor<T>Defaultown value, else the whole item | Defines a path that returns a property of the object to use as value or a function that returns any value.
Unset: own Prefer a primitive id: stable, unique, cheap to submit. Omit it and the item's own |
knownItems Type: ([Known] extends [undefined] ? BbSelectKnownItems : Known) |
|
label requiredType: string | Text content of the label of the element. |
labelAlign Type: FieldCrossAlign | Vertical position of the label block in a side-by-side row; not |
labelMode Type: "outside" | "floating" | "inside" | Label rendering mode. |
labelPosition Type: "left" | "center" | "right" | Sets the text alignment of the label. |
layout Type: Responsive<FieldLayout> | How label and input sit together: |
loading Type: booleanDefaultfalse | Sets the component in a loading state, usually triggering some visual styles. External pending state only, such as a parent form saving. Fetching through a provider drives its own loading state, so mirroring it here does nothing but hide bugs. See example |
loadingText Type: string | String displayed while items are being loaded. |
max Type: number | Maximum number of selectable items when the multiple flag is set. Applies to |
maxSelectedLabels Type: numberDefaultInfinity | Maximum number of labels shown before collapsing to a count summary. Unset, the labels collapse only when they overflow the field. Applies to |
modelValue Type: any | Used by v-model. Can be any serializable type. |
modelValueDebounceTime Type: numberDefault0 | Timeout used to debounce response to changes to modelValue. |
multiple Type: booleanDefaultfalse | Allows the selection of multiple items. The model must already be an array on the first render. A scalar or an unseeded |
name Type: string | Defines the name of the input. Renders one hidden input per value, JSON-stringifying anything that is not a string. In v3 an empty selection posts no field at all, like a native |
offCanvasProps Type: Partial<BbOffCanvasProps> | Props for the phone sheet (the |
persistentHint Type: booleanDefaultfalse | Keeps the hint displayed. |
placeholder Type: string | Text shown in the field while nothing is picked (an empty list has Shows whenever nothing is selected, in |
prefill Type: boolean | "interaction"Default'interaction' | When the options first load:
|
prepend:icon Type: string | Name of the icon to be added at the start of the input. |
pt Type: ({ root?: PtValue | undefined; header?: PtValue | undefined; icon?: PtValue | undefined; panel?: PtValue | undefined; "root:open"?: PtValue | undefined; "header:open"?: PtValue | undefined; "icon:open"?: PtValue | undefined; "panel:open"?: PtValue | undefined; spinner?: PtValue | undefined; clear?: PtValue | undefined; "root:loading"?: PtValue | undefined; "icon:loading"?: PtValue | undefined; "spinner:loading"?: PtValue | undefined; "clear:loading"?: PtValue | undefined; "root:disabled"?: PtValue | undefined; label?: PtValue | undefined; "root:errors"?: PtValue | undefined; "root:warnings"?: PtValue | undefined; "root:readonly"?: PtValue | undefined; "icon:disabled"?: PtValue | undefined; "spinner:disabled"?: PtValue | undefined; "root:selected"?: PtValue | undefined; "header:disabled"?: PtValue | undefined; "header:selected"?: PtValue | undefined; description?: PtValue | undefined; message?: PtValue | undefined; hint?: PtValue | undefined; "icon:errors"?: PtValue | undefined; "icon:warnings"?: PtValue | undefined; "icon:readonly"?: PtValue | undefined; "label:disabled"?: PtValue | undefined; "label:errors"?: PtValue | undefined; "label:warnings"?: PtValue | undefined; "label:readonly"?: PtValue | undefined; "description:disabled"?: PtValue | undefined; "description:errors"?: PtValue | undefined; "description:warnings"?: PtValue | undefined; "description:readonly"?: PtValue | undefined; "message:disabled"?: PtValue | undefined; "message:errors"?: PtValue | undefined; "message:warnings"?: PtValue | undefined; "message:readonly"?: PtValue | undefined; "hint:disabled"?: PtValue | undefined; "hint:errors"?: PtValue | undefined; "hint:warnings"?: PtValue | undefined; "hint:readonly"?: PtValue | undefined; input?: PtValue | undefined; list?: PtValue | undefined; "root:hasValue"?: PtValue | undefined; "description:loading"?: PtValue | undefined; "description:hasValue"?: PtValue | undefined; "message:loading"?: PtValue | undefined; "message:hasValue"?: PtValue | undefined; "hint:loading"?: PtValue | undefined; "hint:hasValue"?: PtValue | undefined; "list:loading"?: PtValue | undefined; "list:disabled"?: PtValue | undefined; "list:errors"?: PtValue | undefined; "list:warnings"?: PtValue | undefined; "list:readonly"?: PtValue | undefined; "list:hasValue"?: PtValue | undefined; "icon:hasValue"?: PtValue | undefined; "label:loading"?: PtValue | undefined; "label:hasValue"?: PtValue | undefined; "itemDescription:loading"?: PtValue | undefined; "itemDescription:disabled"?: PtValue | undefined; "itemDescription:errors"?: PtValue | undefined; "itemDescription:warnings"?: PtValue | undefined; "itemDescription:readonly"?: PtValue | undefined; "itemDescription:hasValue"?: PtValue | undefined; box?: PtValue | undefined; prefix?: PtValue | undefined; suffix?: PtValue | undefined; sheet?: PtValue | undefined; "panel:loading"?: PtValue | undefined; "panel:disabled"?: PtValue | undefined; "panel:errors"?: PtValue | undefined; "panel:warnings"?: PtValue | undefined; "panel:readonly"?: PtValue | undefined; "panel:hasValue"?: PtValue | undefined; "spinner:errors"?: PtValue | undefined; "spinner:warnings"?: PtValue | undefined; "spinner:readonly"?: PtValue | undefined; "spinner:hasValue"?: PtValue | undefined; "clear:disabled"?: PtValue | undefined; "clear:errors"?: PtValue | undefined; "clear:warnings"?: PtValue | undefined; "clear:readonly"?: PtValue | undefined; "clear:hasValue"?: PtValue | undefined; "input:loading"?: PtValue | undefined; "input:disabled"?: PtValue | undefined; "input:errors"?: PtValue | undefined; "input:warnings"?: PtValue | undefined; "input:readonly"?: PtValue | undefined; "input:hasValue"?: PtValue | undefined; "box:loading"?: PtValue | undefined; "box:disabled"?: PtValue | undefined; "box:errors"?: PtValue | undefined; "box:warnings"?: PtValue | undefined; "box:readonly"?: PtValue | undefined; "box:hasValue"?: PtValue | undefined; "prefix:loading"?: PtValue | undefined; "prefix:disabled"?: PtValue | undefined; "prefix:errors"?: PtValue | undefined; "prefix:warnings"?: PtValue | undefined; "prefix:readonly"?: PtValue | undefined; "prefix:hasValue"?: PtValue | undefined; "suffix:loading"?: PtValue | undefined; "suffix:disabled"?: PtValue | undefined; "suffix:errors"?: PtValue | undefined; "suffix:warnings"?: PtValue | undefined; "suffix:readonly"?: PtValue | undefined; "suffix:hasValue"?: PtValue | undefined; "sheet:loading"?: PtValue | undefined; "sheet:disabled"?: PtValue | undefined; "sheet:errors"?: PtValue | undefined; "sheet:warnings"?: PtValue | undefined; "sheet:readonly"?: PtValue | undefined; "sheet:hasValue"?: PtValue | undefined; footer?: PtValue | undefined; activator?: PtValue | undefined; "sheet:open"?: PtValue | undefined; "footer:open"?: PtValue | undefined; "panel:selected"?: PtValue | undefined; "sheet:selected"?: PtValue | undefined; "header:loading"?: PtValue | undefined; "header:errors"?: PtValue | undefined; "header:warnings"?: PtValue | undefined; "header:readonly"?: PtValue | undefined; "header:hasValue"?: PtValue | undefined; "icon:selected"?: PtValue | undefined; "spinner:open"?: PtValue | undefined; "spinner:selected"?: PtValue | undefined; "clear:open"?: PtValue | undefined; "clear:selected"?: PtValue | undefined; "label:open"?: PtValue | undefined; "label:selected"?: PtValue | undefined; "description:open"?: PtValue | undefined; "description:selected"?: PtValue | undefined; "message:open"?: PtValue | undefined; "message:selected"?: PtValue | undefined; "hint:open"?: PtValue | undefined; "hint:selected"?: PtValue | undefined; "input:open"?: PtValue | undefined; "input:selected"?: PtValue | undefined; "box:open"?: PtValue | undefined; "box:selected"?: PtValue | undefined; "prefix:open"?: PtValue | undefined; "prefix:selected"?: PtValue | undefined; "suffix:open"?: PtValue | undefined; "suffix:selected"?: PtValue | undefined; "activator:open"?: PtValue | undefined; "activator:selected"?: PtValue | undefined; "activator:loading"?: PtValue | undefined; "activator:disabled"?: PtValue | undefined; "activator:errors"?: PtValue | undefined; "activator:warnings"?: PtValue | undefined; "activator:readonly"?: PtValue | undefined; "activator:hasValue"?: PtValue | undefined; "list:open"?: PtValue | undefined; "list:selected"?: PtValue | undefined; "itemDescription:open"?: PtValue | undefined; "itemDescription:selected"?: PtValue | undefined; "itemText:open"?: PtValue | undefined; "itemText:disabled"?: PtValue | undefined; "itemText:selected"?: PtValue | undefined; "footer:disabled"?: PtValue | undefined; "footer:selected"?: PtValue | undefined; "itemIcon:open"?: PtValue | undefined; "itemIcon:disabled"?: PtValue | undefined; "itemIcon:selected"?: PtValue | undefined; "footer:loading"?: PtValue | undefined; "itemText:loading"?: PtValue | undefined; "itemIcon:loading"?: PtValue | undefined; "itemText:errors"?: PtValue | undefined; "itemText:warnings"?: PtValue | undefined; "itemText:readonly"?: PtValue | undefined; "itemText:hasValue"?: PtValue | undefined; "footer:errors"?: PtValue | undefined; "footer:warnings"?: PtValue | undefined; "footer:readonly"?: PtValue | undefined; "footer:hasValue"?: PtValue | undefined; "itemIcon:errors"?: PtValue | undefined; "itemIcon:warnings"?: PtValue | undefined; "itemIcon:readonly"?: PtValue | undefined; "itemIcon:hasValue"?: PtValue | undefined; "option:open"?: PtValue | undefined; "option:selected"?: PtValue | undefined; "option:loading"?: PtValue | undefined; "option:disabled"?: PtValue | undefined; "option:errors"?: PtValue | undefined; "option:warnings"?: PtValue | undefined; "option:readonly"?: PtValue | undefined; "option:hasValue"?: PtValue | undefined; "badge:open"?: PtValue | undefined; "badge:selected"?: PtValue | undefined; "badge:loading"?: PtValue | undefined; "badge:disabled"?: PtValue | undefined; "badge:errors"?: PtValue | undefined; "badge:warnings"?: PtValue | undefined; "badge:readonly"?: PtValue | undefined; "badge:hasValue"?: PtValue | undefined; "comma:open"?: PtValue | undefined; "comma:selected"?: PtValue | undefined; "comma:loading"?: PtValue | undefined; "comma:disabled"?: PtValue | undefined; "comma:errors"?: PtValue | undefined; "comma:warnings"?: PtValue | undefined; "comma:readonly"?: PtValue | undefined; "comma:hasValue"?: PtValue | undefined; } & { itemDescription?: PtValue | PtItemFn<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>> | undefined; itemText?: PtValue | PtItemFn<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>> | undefined; itemIcon?: PtValue | PtItemFn<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>> | undefined; option?: PtValue | PtItemFn<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>> | undefined; badge?: PtValue | PtItemFn<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>> | undefined; comma?: PtValue | PtItemFn<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>> | undefined; } & { "root:outline"?: PtValue | undefined; "icon:outline"?: PtValue | undefined; "root:secondary"?: PtValue | undefined; "icon:secondary"?: PtValue | undefined; "spinner:outline"?: PtValue | undefined; "spinner:secondary"?: PtValue | undefined; "clear:outline"?: PtValue | undefined; "clear:secondary"?: PtValue | undefined; "root:ghost"?: PtValue | undefined; "icon:ghost"?: PtValue | undefined; "spinner:ghost"?: PtValue | undefined; "clear:ghost"?: PtValue | undefined; "label:outline"?: PtValue | undefined; "label:secondary"?: PtValue | undefined; "label:ghost"?: PtValue | undefined; "description:outline"?: PtValue | undefined; "description:secondary"?: PtValue | undefined; "description:ghost"?: PtValue | undefined; "message:outline"?: PtValue | undefined; "message:secondary"?: PtValue | undefined; "message:ghost"?: PtValue | undefined; "hint:outline"?: PtValue | undefined; "hint:secondary"?: PtValue | undefined; "hint:ghost"?: PtValue | undefined; "box:outline"?: PtValue | undefined; "box:secondary"?: PtValue | undefined; "box:ghost"?: PtValue | undefined; "prefix:outline"?: PtValue | undefined; "prefix:secondary"?: PtValue | undefined; "prefix:ghost"?: PtValue | undefined; "suffix:outline"?: PtValue | undefined; "suffix:secondary"?: PtValue | undefined; "suffix:ghost"?: PtValue | undefined; "activator:outline"?: PtValue | undefined; "activator:secondary"?: PtValue | undefined; "activator:ghost"?: PtValue | undefined; }) | Passthrough, object form: the same keys as the |
pt:<part> Type: PtValue | ((ctx: PtItemCtx<T, BbSelectPtState, never, BbSelectSlotRow<T, Known>>) => PtItemResult) | Passthrough, attribute form: one attribute per part, |
queryDebounceTime Type: numberDefault500 | Time to wait when the user stops writing in the input before querying data. The component owns the debounce; a hand-rolled one around the provider fights it. See example |
readonly Type: booleanDefaultfalse | Sets the input in a readonly state. |
required Type: booleanDefaultfalse | Sets the input as required. Feeds the asterisk (unless the plugin's |
reverse Type: booleanDefaultfalse | Reverses the layout. Applicable in every direction the order of the label and the input is swapped. |
rules Type: RuleExpression<any> | vee-validate rules for this field. Only inside a Checked when focus leaves both the field and its panel, then on every change while an error shows (the default |
selectable Type: boolean | ((item: T) => boolean)Defaulttrue | Defines whether options are selectable. Can be a global boolean that affects all options or a function that accepts an item and returns a boolean that only affects that item. Non-selectable options are rendered disabled. The only supported way to disable individual options. A |
selectedLabelsFn Type: ((count: number) => string) | Function that returns a string to be displayed when the number of selected labels is greater than |
stash Type: booleanDefaultfalse | Keeps picked options named across searches: a pick stays resolvable (its chip keeps its text) when a later search or a failed load no longer returns it. It follows the model, and does not keep a pick valid: Keeps every previously fetched option resolvable, which is what stops a chip losing its text after a later search. The flip side: on a select with |
transitionDuration Type: numberDefault250 | How long the transition has to last in milliseconds. |
validationLabel Type: string | The field's name in validation messages ( |
validationMode Type: ValidationMode | When the field validates: |
variant Type: InputVariantTypeDefault'outline' | The field box's look, with |
warnings Type: string | string[] | Warning messages under the field, a string or array: amber, in their own |
v-model
Values kept in sync through v-model.
| Name | Description |
|---|---|
modelValue Type: any | Holds a single value, or an array of them under |
Events
| Name | Description |
|---|---|
active Type: (): void | Emitted when the select becomes active (focus enters it). |
blur Type: (event: FocusEvent): void | Emitted when the activator loses focus. Forwards the original DOM |
change Type: (event: Event): void | Emitted on the native |
click Type: (event: MouseEvent): void | Emitted when the activator is clicked. Forwards the original DOM |
focus Type: (event: FocusEvent): void | Emitted when the activator receives focus. Forwards the original DOM |
hide Type: (): void | Emitted as soon as the options surface starts to close. |
inactive Type: (): void | Emitted when focus moves outside the whole select after it was active. Outside a |
input Type: (event: Event): void | Emitted on native |
option:add Type: (text: string): void | Emitted with the typed text when the user confirms a value that is not in the list (Enter in the search field). Binding it keeps the search field writable, which makes the select creatable. Fires with the trimmed query when Enter is pressed and no option is highlighted. Create the record on your side, then push it into |
show Type: (): void | Emitted as soon as the options surface starts to open (the popover, or the sheet on a phone). |
shown Type: (): void | Emitted once the options surface is open and its open transition has finished. |
update:modelValue Type: (value: any): void | Emitted with the new value whenever |
Slots
The listed properties are the ones exposed to the slot scope.
| Name | Description |
|---|---|
append Type: { query: string; focus: () => void; close: () => Promise<void>; } | Content appended inside the input field, after the value area. |
append:outer Type: { query: string; close: () => Promise<void>; } | Content appended outside the input field wrapper. |
chip Type: BbSelectChipSlotProps<T, Known> | Replaces the default badge rendered for each selection in Replaces the badge for each selection in |
description Type: BbSelectDescriptionSlotProps | Replaces the description text. Provided alone (no |
empty Type: { query: string; focus: () => void; error: unknown; } | Content shown when no options match the query or the list is empty. |
footer Type: BbSelectPanelSlotProps | Content pinned to the bottom of the options panel, below the options list. Rendered in both the desktop popover and the adaptive sheet. Renders below the options list in the desktop popover and in the mobile sheet alike. Select-all lives here: the model is yours, so assigning every value to it is the whole implementation. See example |
group Type: BbSelectGroupSlotProps<T> | Replaces the default group header rendered above grouped options. Not called for rows with no group ( Styles the group header only. |
header Type: BbSelectPanelSlotProps | Content pinned to the top of the options panel, above the search field. Rendered in both the desktop popover and the adaptive sheet. Renders above the search field. Derive any summary from your own model rather than from |
label Type: BbSelectLabelSlotProps | Replaces the default label text rendered above the input. |
loading Type: { query: string; } | Content shown inside the options dropdown while items are loading. |
option Type: BbSelectOptionSlotProps<T, Known> | Replaces the default rendering of each option row in the dropdown. With Replaces the row's text, not the selection check: that renders outside the slot and survives any markup. Taller rows need |
prefix Type: object | Content rendered as an inline prefix inside the input field. |
prepend Type: { query: string; focus: () => void; close: () => Promise<void>; } | Content prepended inside the input field, before the value area. |
prepend:outer Type: { query: string; close: () => Promise<void>; } | Content prepended outside the input field wrapper. |
suffix Type: object | Content rendered as an inline suffix inside the input field. |
Renamed and removed
Names from v2 and from earlier 3.0 betas that no longer work, and what to write instead.
allowWritingdisableWritingfails silently- slot
append-outerappend:outerfails silently directionlayoutfails silentlyhasWarninghasWarningsfails silently- slot
no-dataemptyfails silently noDataTextemptyTextfails silently- slot
prepend-outerprepend:outerfails silently showChevronremovedfails silentlyupdateOnAnimationFrameremovedfails silentlyvalidateOnvalidationModefails silentlyAn array of events became one mode (
aggressive|balanced|lazy|submit-only|submit-live). The old defaults (['blur'],['inactive'], a toggle's['update:modelValue', 'change', 'blur']) arebalanced, the new default: delete the prop. A text field on['update:modelValue']isvalidation-mode="aggressive". Set it once on<BbForm validation-mode>instead of per field.vidremovedfails silentlyA display name (v2:
vid="Email address") is nowvalidation-label; a field path (3.0 betas:vid="address.city") is nowname(brackets for a native post:address[city]).check --fixpicks by the value.