vael-ui v0.3.10

Selection

Select

A dropdown for picking one or more values from a list, with search and virtualization.

Install

import { Select } from 'vael-ui'

Playground

import { Select } from 'vael-ui'

<Select placeholder="" :multiple="false" :disabled="false" :invalid="false" size="md" :loading="false" :clearable="false" :maxLabels="0" display="chip" virtualize name="" side="bottom" align="start" :sideOffset="8" :alignOffset="0" closeOnEsc closeOnOutside :forceMount="false" scrollFade motionCss filterPlaceholder="Search..." query="" :items="items">Select</Select>

Props

NameTypeDefaultDescription
itemsreadonly T[]
placeholderstring | undefined
multipleboolean | undefinedfalse
disabledboolean | undefinedfalse
invalidboolean | undefinedfalse
size"md" | "sm" | "lg""md"
loadingboolean | undefinedfalse
clearableboolean | undefinedfalse
maxLabelsnumber | undefined`multiple` only: how many selected items render as chips before collapsing the rest into a "+N" indicator. Default: uncollapsed.
display"text" | "count" | "chip""chip"`multiple` only: how the trigger renders multiple selections. `'chip'` (default) shows removable chips; `'text'` shows comma-joined labels; `'count'` shows a "N selected" summary. Single-select ignores this prop.
virtualizeboolean | SelectVirtualizeConfig | undefinedundefined`true`/`false` forces virtualization on/off; an object also tunes `itemSize`/`overscan`. Default: auto-virtualizes past 100 items.
namestring | undefinedRenders hidden `<input>`(s) so a plain `<form>` post still carries the selection — repeated `name` when `multiple`.
side"top" | "right" | "bottom" | "left""bottom"Which side of the trigger the panel opens on.
align"start" | "end" | "center""start"How the panel aligns against the trigger along that side.
sideOffsetnumber | undefined8Gap between the trigger and the panel, in pixels.
alignOffsetnumber | undefined0Shifts the panel along the alignment axis, in pixels.
closeOnEscboolean | undefinedtrueEscape key closes the panel.
closeOnOutsideboolean | undefinedtrueClicking outside the panel closes it.
beforeClose((done: () => void) => void) | undefinedCustom exit animation; call `done()` when it's complete. Delays the actual close/unmount until then.
forceMountboolean | undefinedfalseWhen true, presence is v-show-driven and owned by the consumer (e.g. AnimatePresence).
teleportTostring | HTMLElement | undefined"body"CSS selector or an actual DOM element — same contract as Vue's own Teleport `to`.
scrollFadeboolean | undefinedtrueMasks the panel's top/bottom edge as its content scrolls under it, signaling there's more.
maxPanelHeightnumber | undefinedCaps the panel's height at this many pixels even when the viewport has room for more — the option list scrolls internally past it instead of the panel growing indefinitely. Omitted keeps today's behavior (only the viewport limits it).
motionCssboolean | undefinedtrueGates the built-in chip enter/exit/reposition transition (`multiple` + `display="chip"` only). `false` skips it entirely — reach for `@chip-enter`/`@chip-leave` instead if you want a consumer-owned animation (GSAP, motion-v) in its place.
filterSelectFilter<T> | undefinedundefinedShows a built-in search box at the top of the panel. `undefined` (default): no box — most lists are short enough that one is just noise. `true`: box + built-in diacritic/case- insensitive label match against `items`. A function: box + your own sync match against the same `items`. `false`: box, but Select does no matching of its own — pair with `v-model:query` and swap `items` yourself (debounced API search, server-side paging). Virtualization already reacts to whatever `items` ends up being, so a remote result set re-virtualizes for free.
filterPlaceholderstring | undefined"Search..."
uiPartial<{ trigger: UiPartValue; value: UiPartValue; positioner: UiPartValue; panel: UiPartValue; header: UiPartValue; filter: UiPartValue; list: UiPartValue; option: UiPartValue; empty: UiPartValue; footer: UiPartValue; }> | undefined
modelValuestring | number | (string | number)[] | null | undefinednull
querystring | undefined""
openboolean | undefinedfalse

Slots

NameTypeDescription
value{ selected: T | T[] | null; }
header{ count: number; total: number; }Above the filter input (if `filter` is on) or the listbox itself. `count`/`total` are handed through for a result-count readout, but the slot is arbitrary content, not just that.
filter{ query: string; onKeydown: (event: KeyboardEvent) => void; }Replaces the built-in filter row entirely — bind your own control straight to `v-model:query` on `<Select>` itself (no need to round-trip through this slot's props for that); `onKeydown` is handed through only so a fully custom input can still opt into arrow/Home/End/Enter listbox navigation the same way the built-in one does.
filter-iconanySwaps just the built-in filter row's leading icon, keeping its `Input` frame.
item{ item: T; active: boolean; selected: boolean; }
emptyany
footeranyBelow the listbox — e.g. a "create new" or "view all" action.

Events

NameTypeDescription
open-change[value: boolean, details: PopoverOpenChangeDetails]
select[item: T]
change[value: string | number | (string | number)[] | null]
reach-end[]
chip-enter[el: Element, done: () => void]
chip-leave[el: Element, done: () => void]
update:open[value: boolean]
update:modelValue[value: string | number | (string | number)[] | null]
update:query[value: string]

Exposed

NameTypeDescription
triggerElunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
panelElunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
positionerElunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
listElunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
filterInputRefunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
placementunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
positionerStyleunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
isClosingunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
openunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
closeunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
cancelCloseunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
activeIndexunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.
scrollToIndexunknownType inference unavailable — vue-component-meta cannot resolve defineExpose on this generic component.