Skip to content

v1 roadmap #324

@TotomInc

Description

@TotomInc

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-select or Vue 2 codebases or just for simple use-cases).

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>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions