VPick API
Every prop, slot, event, and method in one place. Each prop links to the page that explains it in context.
Props
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.
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.
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.
searchable
boolean default falseSwaps the button trigger for an input with type-ahead filtering. No effect with multiple, which always uses that trigger.
filter
(option, query) => boolean default undefinedReplaces the built-in matcher. Receives each option and the current query.
searchNested
boolean default falseIn tree mode, lets a multi-word query match across a node's ancestor path.
closeOnSelect
boolean default see descriptionCloses the list after picking. Defaults to true in single-select and false in multiple; an explicit value applies to both.
searchKeys
string | string[] default undefinedExtra fields on your option objects to search, alongside the label.
fetchOptions
(query: string, context: { signal?: AbortSignal }) => unknown[] | Promise<unknown[]> default undefinedAnswers what the user types with options, from a server or an in-browser search engine, instead of filtering options.
searchDebounce
number default 300Milliseconds to wait after the last keystroke before calling fetchOptions. 0 asks on every keystroke.
searchingText
string default "Searching..."Shown while fetchOptions is working on the typed query.
searchErrorText
string default "Could not search. Click to retry"Shown when fetchOptions rejects. Clicking it asks again.
searchPromptText
string default "Type to search"Shown with fetchOptions when nothing is typed and options is empty.
multiple
boolean default falseAllows more than one selection. v-model becomes an array and the trigger draws chips.
backspaceRemoves
boolean default trueBackspace on an empty search input removes the last chip.
sortValueBy
"ORDER_SELECTED" | "LEVEL" | "INDEX" default "ORDER_SELECTED"Order of the emitted array and of the chips.
defaultExpandLevel
number default undefinedLevels to pre-expand on open. 1 opens top-level branches, 2 opens two levels, and so on.
disableBranchNodes
boolean default falseMakes branches unselectable, so only leaves can be picked. Clicking a branch row expands it instead.
cascade
boolean default trueIn multiple tree mode, selecting a branch selects its descendants. false gives independent nodes.
valueConsistsOf
"LEAF_PRIORITY" | "ALL" | "BRANCH_PRIORITY" | "ALL_WITH_INDETERMINATE" default "LEAF_PRIORITY"Which nodes end up in v-model while cascade is active.
compactChips
boolean default trueWith cascade, merges chips into the topmost fully selected branch. false shows one chip per value entry.
flattenSearchResults
boolean default falseDrops the ancestor rows and the indent from search results, leaving a flat list.
noChildrenText
string default "No sub-options"Shown under an expanded branch whose children array is empty.
loadChildren
(option: unknown) => Promise<unknown[]> default undefinedFetches a branch's children when it first opens. Mark those branches with children: null.
loadOnSelect
boolean default trueTicking an unloaded branch loads its children first. false ticks the branch as its own value with no request.
loadingChildrenText
string default "Loading..."Shown under a branch while its children load.
loadOnSearch
boolean default falseLets a search open and load unloaded branches that match. Off, they stay closed and match by their own label.
loadChildrenErrorText
string default "Could not load. Click to retry"Shown under a branch whose children failed to load. Clicking it retries.
teleportTo
string | HTMLElement default auto-detectedWhere the panel is rendered. Naming a target skips auto-detection; <body> is the fallback.
floatingUi
typeof import("@floating-ui/dom") default undefinedHands positioning to Floating UI: where the dropdown goes, when it moves and when it hides. VPick still renders it into its container. Pass the library itself.
align
"start" | "end" default "start"Which edge of the trigger the panel lines up with. Follows the writing direction.
strategy
"auto" | "absolute" | "fixed" default "auto"How the panel is anchored once it is rendered.
hideWhenDetached
boolean default trueHides the panel while its trigger is scrolled out of view. With floatingUi, Floating UI's hide decides.
bodyLock
boolean default see descriptionLocks scrolling while open. Unset, defaults to true in button mode and false in searchable mode.
alwaysOpen
boolean default falseRenders the list inline in the page rather than as a dropdown. It cannot be closed.
valueFormat
"id" | "object" default "id"Whether v-model holds plain values or your original option objects.
Slots
| Slot | Scope | Description |
|---|---|---|
icon | none | Custom chevron icon. Shown when not loading. |
loading | none | Custom loading indicator. Shown when loading is true. |
clear | none | Custom clear button content. Shown when clearable and a value is selected. |
empty | { query: string } | Custom empty state, for no options at all or a search that matches nothing. |
no-children | { option: OptionItem } | Custom content for an expanded branch whose children array is empty. Defaults to noChildrenText. |
no-children-icon | { option: OptionItem } | Icon for that same row, rendered on the column the leaf checkboxes use. |
value-label | { option: OptionItem } | Custom label for the selected value: the trigger label in single mode, each chip in multiple mode. |
option-label | { option: OptionItem, isBranch: boolean, isExpanded: boolean, depth: number } | Custom label for each row in the list. The chevron, checkbox and check icon stay put. |
Usage for each is on the Slots page.
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | any | Emitted when the selection changes. Vue 2 emits input, which is what v-model listens for there. |
search | string | Emitted on every keystroke in searchable mode. |
select | object | Emitted when an option is picked. Payload is your original option object. |
deselect | object | Emitted when an option is unpicked in multiple mode. Same payload as select. |
open | none | Emitted when the list opens. An alwaysOpen list starts open, so it does not emit this on mount. |
close | none | Emitted when the list closes, whether by Escape, an outside click, a pick, or becoming disabled. |
select and deselect hand back the exact object you passed in options. See when deselect fires for the two cases that are not obvious.
Methods
Reach these through a template ref.
| Method | Description |
|---|---|
focus() | Moves focus to the control. In searchable and multiple mode the list opens, the same as tabbing into it. |
<script setup>
import { ref } from "vue"
const pick = ref()
</script>
<template>
<VPick ref="pick" :options="options" />
<button @click="pick.focus()">Edit</button>
</template>CSS custom properties
Theming is documented separately, since the variables are shared with VPickNative. See Theming.
Types
interface OptionItem {
label: string
value: any
disabled?: boolean
// An array, even an empty one, marks this node as a branch.
children?: OptionItem[]
// Set by Vue Pick, not by you: the original object you passed in.
// Handed back by `select`/`deselect` and available in slots.
raw?: unknown
}
interface OptionGroup {
label: string
disabled?: boolean
options: OptionItem[]
}
type OptionOrGroup = OptionItem | OptionGroupSee the Data Shape guide for reading your own shapes without transforming them.