VPick
A custom dropdown triggered by a button, with full keyboard navigation and group labels.
This page covers the parts every VPick has. Each of the bigger capabilities has its own page:
| Page | What it covers |
|---|---|
| Search | Type-ahead filtering, clearing, empty states |
| Multiselect | Multiple values, chips, select and deselect |
| Tree Select | Nested options, cascade selection, searching a tree |
| Slots | Replacing labels, icons, and the empty state |
| Positioning | Where the panel renders, scroll containers, inline mode |
| Forms | Labelling, submission, validation |
| Accessibility | Keyboard navigation, ARIA roles, screen readers |
| API | Every prop, slot, event, and method in one place |
Options
Accepts the same options shape as VPickNative. Flat arrays and grouped arrays both work, and groups are detected automatically when an item has an options array.
Grouped
Separators
Use separators to render a horizontal divider between adjacent groups.
Custom data shape
Use labelKey, valueKey, disabledKey, and groupOptionsKey to pass data straight from your API without mapping. See the Data Shape guide for the full reference.
labelKey also accepts an array, used as a fallback chain where the first key with a non-empty value wins. Useful when records are inconsistent:
<VPick :options="options" :label-key="['label', 'name']" value-key="id" />States
Disabled
Loading
Error
Appearance
Rotate icon
Rotates the chevron 180 degrees when the dropdown is open.
Scrollable
Long option lists scroll inside the dropdown. Max height is controlled by --vpick-listbox-max-height (default 16rem).
Sizing
By default, the trigger hugs its content (--vpick-width: fit-content) and the dropdown matches the trigger width at minimum. Give the trigger an explicit width and the dropdown will follow.
<VPick v-model="selected" :options="options" style="--vpick-width: 18rem" />Options wider than the trigger make the dropdown grow. To pin both widths identical and truncate long labels, also cap the listbox:
<VPick
v-model="selected"
:options="options"
style="
--vpick-width: 18rem;
--vpick-listbox-max-width: var(--vpick-trigger-width);
"
/>| Variable | Default | Effect |
|---|---|---|
--vpick-width | fit-content | Trigger width. |
--vpick-listbox-min-width | --vpick-trigger-width | Minimum dropdown width. |
--vpick-listbox-max-width | calc(100vw - 16px) | Maximum dropdown width. |
--vpick-listbox-max-height | 16rem | Maximum dropdown height before scrolling. |
--vpick-trigger-width is measured and set by Vue Pick on every open, so read it rather than assign it.
Object values
By default v-model holds plain values:
selected = ["apple", "banana"]Set valueFormat="object" and it holds your original option objects instead:
selected = [
{ id: "apple", label: "Apple", price: 3 },
{ id: "banana", label: "Banana", price: 2 },
]Useful when you need other fields off the selection and would otherwise look them up yourself. Both controls below hold the same selection:
<VPick
v-model="selected"
:options="fruit"
label-key="label"
value-key="id"
value-format="object"
/>Objects you pass back in are matched by valueKey, not by identity, so a rebuilt object literal still resolves:
selected = { id: "apple" } // matches the Apple optionThe hidden <select> used for form submission always posts plain values, since a form field cannot carry an object.
Core props
The props every VPick takes. The rest are listed on the page for the feature they belong to, and all of them together on the API Reference.
modelValue
any default undefinedSelected value. Use v-model for two-way binding. In Vue 2 the prop is value.
placeholder
string default undefinedText shown when no value is selected.
disabled
boolean default falseDisables the control.
loading
boolean default falseShows a spinner and disables interaction.
error
string default undefinedError message. Applies error styling and aria-invalid.
id
string default undefinedHTML id, applied to the control itself so a <label for> resolves to it.
required
boolean default falseHTML required attribute.
ariaLabel
string default undefinedaria-label, for when there is no visible label.
ariaDescribedby
string default undefinedaria-describedby, for wiring up hint or error text.
Data shape
labelKey
string | string[] default "label"Key to read each option's visible label from. An array acts as a fallback chain: the first key with a non-empty value wins.
childrenKey
string default "children"Key for nested children. Any option carrying that array turns tree mode on.
Appearance
separators
boolean default falseDraws a divider between adjacent groups in the list.
rotateIcon
boolean default falseRotates the trigger chevron 180 degrees while open.
animate
boolean default trueAnimates the multiselect chips. false adds and removes them outright.
optionAttrs
(option) => object default undefinedExtra attributes for each option row, such as test ids. Core attributes like role and aria-* cannot be overridden.
classes
object default {}Extra classes for each part, such as trigger, chip or option. chip and option also take (option) => string.