vue-superselect
v1.0.0
Published
Headless, accessible, TypeScript-first select/combobox for Vue 3
Maintainers
Readme
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.
Install
npm install vue-superselectVue 3.5+ required. @floating-ui/vue is an optional peer dependency for smart dropdown positioning.
Quick Start
<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..." aria-label="Fruit" />
</SelectControl>
<SelectContent>
<SelectOption
v-for="fruit in fruits"
:key="fruit"
:value="fruit"
:label="fruit"
>
{{ fruit }}
</SelectOption>
</SelectContent>
</SelectRoot>
</template>The library ships zero CSS. Add your own classes and styles.
Features
- Headless: no shipped CSS, full control over rendering via scoped slots
- Accessible: WAI-ARIA combobox pattern, keyboard navigation, screen reader announcements
- TypeScript: strict mode, full generic inference, typed props and slots
- Single and multi-select:
v-modelwithmultiple, tags, max limits,hideSelected - Filtering: built-in case-insensitive filter, custom filter functions, debounce, IME-safe
- Positioning: optional
@floating-ui/vueintegration with auto-flip, teleport support - Composable API:
useSelect<T>()with prop getters for full DOM control - Tree-shakeable:
sideEffects: false, ESM + CJS builds,/*#__PURE__*/annotations
Components
| Component | Purpose |
|-----------|---------|
| SelectRoot | State container. Manages selection, filtering, keyboard, and ARIA. |
| SelectControl | Wrapper around the input/tags area. |
| SelectInput | Search/filter input field. |
| SelectContent | Dropdown container with positioning. |
| SelectOption | Individual selectable option with scoped slot props. |
| SelectTag | Removable tag for multi-select. |
| SelectTrigger | Toggle button for the dropdown. |
| SelectClear | Button to clear the current selection. |
| SelectEmpty | Shown when no options match the filter. |
| SelectLiveRegion | Screen reader announcements. |
Composable API
For full control over the rendered DOM:
import { useSelect } from 'vue-superselect'
const {
getRootProps,
getInputProps,
getListboxProps,
getOptionProps,
isOpen,
value,
visibleItems,
} = useSelect({
items: options,
labelKey: 'label',
valueKey: 'id',
})Spread prop getters on your own elements:
<div v-bind="getRootProps()">
<input v-bind="getInputProps()" />
<ul v-bind="getListboxProps()">
<li v-for="item in visibleItems" :key="item.id" v-bind="getOptionProps(item)">
{{ item.label }}
</li>
</ul>
</div>Keyboard Navigation
| Key | Action |
|-----|--------|
| Arrow Down/Up | Navigate options |
| Enter | Select highlighted option |
| Escape | Close dropdown; pressing again clears input query |
| Tab | Move focus (or select highlighted option when selectOnTab is enabled) |
| Backspace | Remove last tag (multi-select, empty input) |
| Home/End | Jump to first/last option |
Browser Support
Modern browsers (Chrome, Firefox, Safari, Edge). No IE11.
License
MIT
