Components

Select

Single or multiple listbox select with keyboard navigation, typeahead, and form submission.

Select renders a trigger and a role="listbox" popup. It supports single or multiple values, labels, separators, typeahead, cancelable changes, and Field metadata without a nested subcomponent tree.

Popup placement flips when preferred side lacks room, clamps to viewport, and follows anchor/content resize and ancestor scrolling.

Use it when the user must choose from a known list. Use autocomplete when the same select needs lightweight filtering. Use Combobox when the text input itself is the primary interaction.

Anatomy

  • #trigger: Custom trigger content. Use triggerProps when rendering your own interactive trigger.
  • #value: Selected value content inside the trigger.
  • #option: Content inside each generated role="option" row.
  • #group-label: Content for non-selectable label rows.

The trigger, listbox, options, indicator, separators, and hidden native select are generated by the component. Style those generated parts with the matching ui keys.

Usage

Selected: pro

Open the list and type to filter suggestions.

Selected: none | Search: empty

Examples

Multiple selection

Set multiple and bind v-model to string[]. Selected options stay open so users can toggle more than one item.

<script setup lang="ts">
import { ref } from "vue";
import { Select } from "akaza-ui";

const permissions = ref(["read"]);
const options = [
  { value: "read", label: "Read" },
  { value: "write", label: "Write" },
  { value: "deploy", label: "Deploy" },
];
</script>

<template>
  <Select v-model="permissions" multiple :options="options" />
</template>

Grouped options

Use type: "label" and type: "separator" for non-selectable rows. They are skipped by keyboard navigation.

<template>
  <Select
    v-model="role"
    :options="[
      { type: 'label', label: 'Project' },
      { value: 'viewer', label: 'Viewer' },
      { value: 'editor', label: 'Editor' },
      { type: 'separator' },
      { type: 'label', label: 'Admin' },
      { value: 'owner', label: 'Owner' },
    ]"
  />
</template>

Autocomplete filtering

Set autocomplete to render a search input inside the popup. Focus moves into the search input when opened; that input owns aria-activedescendant and Arrow/Enter/Escape navigation. Bind v-model:search when search text should drive async loading or external filtering.

<script setup lang="ts">
import { ref } from "vue";

const value = ref("");
const search = ref("");
</script>

<template>
  <Select
    v-model="value"
    v-model:search="search"
    autocomplete
    :options="options"
    search-placeholder="Filter options"
  />
</template>

Field integration

Place Select inside Field to inherit id, name, required, disabled state, invalid state, and aria-describedby. Required/native invalid state is revealed after selection, blur, or invalid submit; it is not shown on initial render.

<template>
  <Field label="Server region" name="region" required>
    <Select v-model="region" :options="regions" placeholder="Choose region" />
  </Field>
</template>

Custom option row

Use #option to render richer option content. The component still owns role="option", selection state, highlighting, and click handling.

<template>
  <Select v-model="region" :options="regions">
    <template #option="{ label, description, isSelected }">
      <span aria-hidden="true">{{ isSelected ? "✓" : "" }}</span>
      <span>
        <strong>{{ label }}</strong>
        <small>{{ description }}</small>
      </span>
    </template>
  </Select>
</template>

Cancel a selection

value-change fires before the model changes. Call details.cancel() to block a value.

<template>
  <Select
    v-model="role"
    :options="roles"
    @value-change="(value, details) => value === 'owner' && details.cancel()"
  />
</template>

API Reference

Props

PropTypeDefaultDescription
optionsSelectOption[]requiredOptions rendered in the listbox.
valueKeystringObject key used as option value. Falls back to value, then label.
labelKeystring"label"Object key used as option label.
descriptionKeystring"description"Object key used as option description.
disabledKeystring"disabled"Object key used as option disabled state.
placeholderstring"Select option"Text shown when no value is selected.
multiplebooleanfalseEnables multi-select. v-model should be string[].
nullableValuestring""Native empty option value for single select.
idstringfield idTrigger id.
namestringfield nameForm field name. Renders a hidden native select.
requiredbooleanfalseRequired state.
disabledbooleanfalseDisables trigger and options.
invalidbooleanfalseSets invalid attrs.
loopbooleantrueArrow navigation wraps.
autocompletebooleanfalseRenders a search input in the popup and filters visible options.
filter(option, search) => booleanlabel/description contains searchCustom autocomplete filter.
loadingbooleanfalseShows loading slot/content inside the popup.
emptyLabelstring"No options found."Default empty state text.
searchPlaceholderstring"Search options..."Search input placeholder.
resetSearchOnSelectbooleanfalseClears search after selection.
highlightOnHoverbooleantruePointer hover updates highlighted option.
side"top" | "right" | "bottom" | "left""bottom"Popup side.
align"start" | "center" | "end""start"Popup alignment.
sideOffsetnumber6Popup offset in px.
ariaLabelstringAccessible label when no visible label exists.
ariaLabelledbystringAccessible label id.
ariaDescribedbystringfield description/errorAccessible description ids.
uiSelectUiClasses for structural parts.

Emits

EventPayloadDescription
open-change(open, details)Fired before popup opens/closes. details.cancel() prevents the change.
value-change(value: string | string[], details)Fired before selected value updates. details.cancel() prevents the update.
search-change(value: string, details)Fired before autocomplete search updates. details.cancel() prevents the update.

Slots

SlotPropsDescription
triggerisOpen, selectedOption, selectedOptions, selectedValue, selectedValues, selectedLabel, placeholder, triggerProps, open, close, toggleCustom trigger content.
valueoption, options, value, values, labelCustom selected value.
optionoption, value, label, description, isSelected, isHighlighted, isDisabled, selectCustom option row.
group-labeloption, labelCustom label row for type: "label" options.
emptyEmpty state for autocomplete filtering.
loadingLoading state content.

Option Shape

KeyTypeDescription
type"item" | "label" | "separator"Row type. Omit for selectable items.
valuestring | numberSubmitted value for selectable items.
labelstringVisible label.
descriptionstringOptional description.
disabledbooleanDisables a selectable item.

UI Options

KeyDescription
rootRoot wrapper.
nativeSelectHidden native select used for form submission.
triggerTrigger button.
valueSelected value wrapper.
placeholderPlaceholder text.
iconDefault chevron icon.
searchInputAutocomplete search input.
contentListbox popup.
viewportScrollable viewport inside popup.
emptyEmpty state.
loadingLoading state.
groupLabelNon-selectable label row.
separatorSeparator row.
optionOption row.
indicatorSelected indicator inside an option.
optionTextOption text wrapper.
optionLabelOption label.
optionDescriptionOption description.

Styling Hooks

UI keyCSS classData attrs
rootakaza-selectdata-akaza-state, data-akaza-side, data-akaza-align, data-akaza-disabled, data-akaza-invalid, data-akaza-filled, data-akaza-focused
nativeSelectakaza-select-native
triggerakaza-select-triggerSame select state attrs plus ARIA combobox attrs via trigger props
valueakaza-select-value
placeholderakaza-select-placeholder
iconakaza-select-icon
searchInputakaza-select-search-inputrole="searchbox", aria-controls, aria-activedescendant, aria-expanded
contentakaza-select-contentdata-akaza-state, data-akaza-side, data-akaza-align, --akaza-select-anchor-width, --akaza-select-anchor-height, --akaza-select-available-width, --akaza-select-available-height, --akaza-select-transform-origin, --akaza-select-duration
viewportakaza-select-viewport
emptyakaza-select-empty
loadingakaza-select-loading
groupLabelakaza-select-group-label
separatorakaza-select-separator
optionakaza-select-optiondata-akaza-state, data-akaza-highlighted, data-akaza-disabled, aria-disabled
indicatorakaza-select-indicator
optionTextakaza-select-option-text
optionLabelakaza-select-option-label
optionDescriptionakaza-select-option-description

Plain class applies to the root wrapper. Use ui.trigger, ui.content, and ui.option for internal parts.

Popup entry and exit use a subtle side-aware structural transition. Override --akaza-select-duration to change its 120ms duration. Reduced-motion preference shortens it automatically.

Native data-akaza-invalid appears after interaction or invalid submit. Controlled invalid state from the invalid prop or parent Field appears immediately.

Keyboard

KeyBehavior
Enter / SpaceOpen select, or select/toggle highlighted option.
ArrowDown / ArrowUpOpen select and move highlight.
Home / EndMove highlight to first/last enabled option.
EscapeClose popup.
printable characterTypeahead to matching option label.