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.
Install
npm install vue-pick
// main.js, in place of "vue-select/dist/vue-select.css"
import "vue-pick/style.css"
import { VPick } from "vue-pick/vue2" // while on Vue 2.7
import { VPick } from "vue-pick" // after the upgrade
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 />
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 />
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 }))
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.
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)