DEV Community

Cover image for Migrate vue-select to a Vue 3 compatible library
Syazwan
Syazwan

Posted on

Migrate vue-select to a Vue 3 compatible library

vue-select's stable release (3.20.4) is Vue 2 only. The Vue 3 version has been at 4.0.0-beta.6 since November 2022.

If it's one of the things holding back your Vue 3 upgrade, you can replace it before the upgrade. Swap it while you're still on 2.7, then upgrade Vue later without touching your selects again.

This walkthrough uses Vue Pick, which runs on both 2.7 and 3 with the same props.

Vue Pick in multiselect mode with two chips selected and the list open

Install

npm install vue-pick
Enter fullscreen mode Exit fullscreen mode
// main.js, in place of "vue-select/dist/vue-select.css"
import "vue-pick/style.css"
Enter fullscreen mode Exit fullscreen mode
import { VPick } from "vue-pick/vue2" // while on Vue 2.7
import { VPick } from "vue-pick"      // after the upgrade
Enter fullscreen mode Exit fullscreen mode

When you move to Vue 3, that import path is the only line that changes.

Check what v-model holds

This is the step that causes bugs if you skip it. vue-select puts the whole option object in v-model, unless you pass reduce.

If you use reduce, name the field with value-key:

<!-- before -->
<v-select v-model="countryId" :options="countries" :reduce="(c) => c.id" />

<!-- after -->
<v-pick v-model="countryId" :options="countries" value-key="id" searchable clearable />
Enter fullscreen mode Exit fullscreen mode

If you don't, add value-format="object" so your data keeps the same shape:

<v-pick v-model="country" :options="countries" value-key="id" value-format="object" searchable clearable />
Enter fullscreen mode Exit fullscreen mode

Turn search and clear back on

vue-select is searchable and clearable by default. Vue Pick isn't, which is why both examples above add searchable clearable.

In multiple mode, Vue Pick also stays open after each pick. Add :close-on-select="true" if you want the old behavior.

Plain string options like ["Apple", "Banana"] need to become objects once:

const options = fruits.map((f) => ({ label: f, value: f }))
Enter fullscreen mode Exit fullscreen mode

v-model still holds the plain string.

Letting an agent do the bulk of it

The full prop, event and slot mapping is in the vue-select migration guide. The page also has a prompt you can paste into Claude Code, Cursor or Copilot. It points the agent at a plain-text copy of the guide and leaves a TODO wherever there's no match, instead of guessing.

The copy-paste agent prompt on the vue-select migration guide

If you wrap vue-select in your own component, migrate the wrapper first. Every page that uses it moves over at once.

Top comments (0)