---
url: /components/vpick.md
description: >-
  A fully accessible custom dropdown for Vue 2.7 and Vue 3 with keyboard
  navigation, group labels, slots, and ARIA support.
---

# 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](/components/vpick/search)               | Type-ahead filtering, clearing, empty states            |
| [Multiselect](/components/vpick/multiselect)     | Multiple values, chips, `select` and `deselect`         |
| [Tree Select](/components/vpick/tree-select)     | Nested options, cascade selection, searching a tree     |
| [Slots](/components/vpick/slots)                 | Replacing labels, icons, and the empty state            |
| [Positioning](/components/vpick/positioning)     | Where the panel renders, scroll containers, inline mode |
| [Forms](/components/vpick/forms)                 | Labelling, submission, validation                       |
| [Accessibility](/components/vpick/accessibility) | Keyboard navigation, ARIA roles, screen readers         |
| [API](/components/vpick/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](/guide/data-shape) 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:

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

```vue
<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:

```vue
<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:

```js
selected = ["apple", "banana"]
```

Set `valueFormat="object"` and it holds your original option objects instead:

```js
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:

```vue
<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:

```js
selected = { id: "apple" } // matches the Apple option
```

The 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](/components/vpick/api).

### Data shape

### Appearance
