- 
                Notifications
    You must be signed in to change notification settings 
- Fork 14
Open
Description
Summary
v1 will introduce a dual-API design:
- Low-level primitive components (Radix-Vue/Reka-UI style) for maximum flexibility and composition.
- High-level default export (Select) that assembles primitives to preserve today’s DX with sensible defaults.
- This is a mandatory requirement, as we still want to provide an easy solution for developers (especially when migrating from vue-selector Vue 2 codebases or just for simple use-cases).
 
- This is a mandatory requirement, as we still want to provide an easy solution for developers (especially when migrating from 
This will be a breaking release.
Motivation
- Provide escape hatches for complex, edge-case UX (infinite scrolling, floating-ui menu).
- Preserve a simple, batteries-included DX for common use cases.
- Improve type-safety, accessibility, and performance.
- Establish a clearer separation of concerns to keep code scannable and maintainable.
Goals
- Low-level primitives with single responsibilities and predictable APIs.
- Default assembled <Select />providing near drop-in behavior for most users.
- Strong TypeScript types for v-model, props, events, slots, and options.
- First-class accessibility following WAI-ARIA best-practices: keyboard nav, ARIA, focus management.
- Robust tests, playground demos, and docs.
- Ideally, migrate documentation template to NuxtUI docs template (which is free now, thanks to NuxtUI v4).
 
Breaking Changes
- Component API re-organization.
- Slots possibly removed and/or renamed.
- Option shape refined (e.g., normalized value, label; custom mappers replace implicit inference).
- Menu/indicator/multi-value rendering delegated to primitives by default (customizable via slots).
- Deprecation of ambiguous props and implicit behaviors; explicit mapping/configuration instead.
- Re-export paths may change (named exports under @/primitives, default export under root).
High-level design
- SelectRoot (state + context provider)
- SelectTrigger (button/input anchor)
- SelectInput (search input, optional)
- SelectIndicator (chevron/loading indicators)
- SelectValue (single/multi display)
- SelectPopover (portal + positioning)
- SelectListbox (virtualized list container)
- SelectOption (option item)
- SelectNoOptions (empty state)
- SelectTag (chip for multi values)
- SelectClear (clear selection)
- SelectSeparator, SelectGroup, SelectGroupLabel (optional)
Key principles thanks to this high-level design:
- Each primitive manages a single concern.
- Cross-component state is conveyed via provide/inject.
- Strong props/events per primitive; no hidden cross effects.
Example usage:
<script setup lang="ts">
import {
  SelectRoot,
  SelectTrigger,
  SelectIndicator,
  SelectInput,
  SelectPopover,
  SelectListbox,
  SelectOption,
  SelectValue,
  SelectNoOptions,
  SelectClear,
} from 'vue3-select-component/primitives'
const options = [
  { value: 'js', label: 'JavaScript' },
  { value: 'ts', label: 'TypeScript' },
]
const model = ref<string | null>(null)
</script>
<template>
  <SelectRoot v-model="model" :options="options" searchable>
    <SelectTrigger>
      <SelectValue placeholder="Pick a language" />
      <SelectIndicator />
      <SelectClear />
    </SelectTrigger>
    <SelectPopover>
      <SelectInput />
      <SelectListbox>
        <SelectNoOptions>No results</SelectNoOptions>
        <SelectOption
          v-for="opt in options"
          :key="opt.value"
          :value="opt.value"
          :label="opt.label"
        />
      </SelectListbox>
    </SelectPopover>
  </SelectRoot>
</template>High-level assembled <Select />
Example usage:
<script setup lang="ts">
import Select from 'vue3-select-component'
const options = [
  { value: 'cat', label: 'Cat' },
  { value: 'dog', label: 'Dog' },
]
const value = ref<string | null>(null)
</script>
<template>
  <Select
    v-model="value"
    :options="options"
    placeholder="Select an animal"
    searchable
    clearable
  />
</template>PlainBane
Metadata
Metadata
Assignees
Labels
No labels