If you've worked with Vue, chances are you came across to solve all three. It's a headless, accessible, TypeScript-first select/combobox component for Vue 3.
npm install vue-superselect
Headless means it ships zero CSS. You bring your own styles -- classes, Tailwind, CSS-in-JS, whatever your project uses. No more fighting a component's built-in stylesheet.
<script setup lang="ts">
import { ref } from 'vue'
import {
SelectRoot,
SelectControl,
SelectInput,
SelectContent,
SelectOption,
} from 'vue-superselect'
const selected = ref<string | null>(null)
const fruits = ['Apple', 'Banana', 'Cherry', 'Grape', 'Orange']
</script>
<template>
<SelectRoot v-model="selected">
<SelectControl>
<SelectInput placeholder="Pick a fruit..." />
</SelectControl>
<SelectContent>
<SelectOption
v-for="fruit in fruits"
:key="fruit"
:value="fruit"
:label="fruit"
>
{{ fruit }}
</SelectOption>
</SelectContent>
</SelectRoot>
</template>
Two APIs, one library
vue-superselect gives you two ways to build selects, depending on how much control you need.
Compound components are the primary API. They use Vue's provide/inject to share state, so you compose them declaratively in your template. This is the approach most projects should start with -- it's concise, readable, and handles all the ARIA attributes automatically.
The composable API (useSelect()) is for when you need full control over the rendered DOM. Instead of components, you get prop getter functions that return the right attributes for each element. You spread them onto your own <input>, <ul>, and <li> elements with v-bind. This is useful for design system integrations, custom animations, or when you want to render something the compound components don't support.
<script setup lang="ts">
import { onMounted, onBeforeUnmount } from 'vue'
import { useSelect } from 'vue-superselect'
import type { CollectionItem } from 'vue-superselect'
const fruits = ['Apple', 'Banana', 'Cherry', 'Grape', 'Orange']
const {
getRootProps,
getInputProps,
getListboxProps,
getOptionProps,
isOpen,
value,
visibleItems,
registerItem,
unregisterItem,
} = useSelect<string>()
const items: CollectionItem<string>[] = fruits.map((fruit, i) => ({
id: `fruit-${i}`,
value: fruit,
label: fruit,
disabled: false,
element: null,
}))
onMounted(() => items.forEach(registerItem))
onBeforeUnmount(() => items.forEach((item) => unregisterItem(item.id)))
</script>
<template>
<div v-bind="getRootProps()">
<input v-bind="getInputProps({ placeholder: 'Search fruits...' })" />
<ul v-if="isOpen" v-bind="getListboxProps()">
<li
v-for="item in visibleItems"
:key="item.id"
v-bind="getOptionProps(item)"
>
{{ item.label }}
</li>
</ul>
</div>
</template>
Multi-select with tags
Multi-select is a first-class feature. Set multiple on SelectRoot and the v-model becomes an array. Add SelectTag for removable tags, and hide-selected to filter out already-chosen options from the dropdown.
<script setup lang="ts">
import { ref } from 'vue'
import {
SelectRoot,
SelectControl,
SelectInput,
SelectContent,
SelectOption,
SelectTag,
} from 'vue-superselect'
const selected = ref<string[]>([])
const skills = ['Vue.js', 'TypeScript', 'React', 'Node.js', 'Python', 'Go']
</script>
<template>
<SelectRoot v-model="selected" multiple hide-selected>
<SelectControl v-slot="{ selectedItems, removeItem }">
<SelectTag
v-for="item in selectedItems"
:key="String(item.value)"
:value="item.value"
:label="item.label"
@remove="removeItem"
/>
<SelectInput placeholder="Select skills..." />
</SelectControl>
<SelectContent>
<SelectOption
v-for="skill in skills"
:key="skill"
:value="skill"
:label="skill"
>
{{ skill }}
</SelectOption>
</SelectContent>
</SelectRoot>
</template>
TypeScript all the way down
vue-superselect is built in TypeScript strict mode with full generic inference. When you pass typed items, the v-model value, slot props, and event payloads are all correctly typed. No any, no manual casting.
interface User {
id: number
name: string
role: 'admin' | 'member'
}
// v-model is correctly typed as number | null
// SelectOption slot props know about User
What else?
The full feature list:
Accessible by default -- WAI-ARIA combobox pattern, full keyboard navigation, screen reader announcements via a live region
Filtering -- built-in case-insensitive search, custom filter functions, configurable debounce, IME-safe
Dropdown positioning -- optional@floating-ui/vueintegration for auto-flip and teleport support
Tree-shakeable --sideEffects: false, ESM + CJS dual builds,/*#__PURE__*/annotations on all components
Small -- under 12 kB gzipped for the full library
Coming from vue-select?
There's a includes a combobox component, and
GitHub:
I'd love to hear what you think. If you run into issues, please open a GitHub issue -- I'm actively maintaining this and plan to ship Option Groups, Form Integration, and Async Data Loading in the next releases.
Headless, accessible, TypeScript-first select/combobox for Vue 3
vue-superselect
Headless, accessible, TypeScript-first select/combobox for Vue 3.
Zero runtime CSS. Full keyboard navigation. WAI-ARIA combobox pattern. Dual API: compound components or useSelect() composable.
Community-Analysen & Experten-Meinungen 0
Verwandte Story-Cluster & Quellen (Vektor-KI)
Ähnliche Beiträge
Auch interessante Nachrichten vue-select is abandoned. Here's what I built to replace it.
Thematisch verwandte Begriffe: vueselect, abandoned, Heres, what · 6 Treffer
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
SOCIAL SHARE CARD GENERATOR