Raccourci clavier : Ctrl + K
Commencer

Sélecteur

VSelect choisit une ou plusieurs valeurs dans une liste, comme un <select> natif, avec l’apparence de VCombobox. Rien ne se saisit : les lettres tapées sur le champ mettent en évidence l’option correspondante.

Utilisation

vue
<script setup lang="ts">
import { ref } from 'vue'
import { VSelect } from 'vectis-ui'

const country = ref('')

const options = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'ch', label: 'Switzerland' },
]
</script>

<template>
  <VSelect
    v-model="country"
    :options="options"
    aria-label="Country"
    placeholder="Choose a country"
  />
</template>

Exemples

Label et texte d'aide

Utilisez label pour nommer le champ et hint pour le texte d’aide. Un clic sur le label ouvre la liste.

vue

The country shown on your invoices

<script setup lang="ts">
import { ref } from 'vue'
import { VSelect } from 'vectis-ui'

const country = ref('')

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'ch', label: 'Switzerland' },
]
</script>

<template>
  <div class="column">
    <VSelect
      v-model="country"
      :options="countries"
      label="Billing country"
      hint="The country shown on your invoices"
      placeholder="Choose a country"
    />
  </div>
</template>

<style scoped>
.column {
  max-inline-size: 26rem;
}
</style>

Tailles

size ajuste le champ et les lignes d’options. compact réduit la hauteur du champ.

vue
<script setup lang="ts">
import { VSelect } from 'vectis-ui'

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'ch', label: 'Switzerland' },
]

const rows = (['sm', 'md', 'lg'] as const).flatMap((size) => [
  { key: size, size, compact: false, label: size },
  { key: `${size}-compact`, size, compact: true, label: `${size}, compact` },
])
</script>

<template>
  <div class="column">
    <VSelect
      v-for="row in rows"
      :key="row.key"
      :options="countries"
      model-value="fr"
      :size="row.size"
      :compact="row.compact"
      :label="row.label"
    />
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  gap: var(--vectis-space-5);
  max-inline-size: 26rem;
}
</style>

États

Utilisez disabled, readonly et invalid pour les états du champ, et clearable pour effacer la sélection. Un champ en lecture seule reste focalisable, mais sa liste ne s’ouvre jamais.

vue

The cross empties the selection

For a rule the browser cannot check by itself

Set by your subscription

<script setup lang="ts">
import { ref } from 'vue'
import { VSelect } from 'vectis-ui'

const chosen = ref('fr')

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'mc', label: 'Monaco', disabled: true },
  { value: 'ch', label: 'Switzerland' },
]
</script>

<template>
  <div class="column">
    <VSelect
      v-model="chosen"
      :options="countries"
      clearable
      label="Clearable"
      hint="The cross empties the selection"
      placeholder="Choose a country"
    />

    <VSelect
      :options="countries"
      model-value="fr"
      invalid
      label="Invalid"
      hint="For a rule the browser cannot check by itself"
    />

    <VSelect :options="countries" model-value="fr" disabled label="Disabled" />

    <VSelect
      :options="countries"
      model-value="fr"
      readonly
      label="Read-only"
      hint="Set by your subscription"
    />
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  gap: var(--vectis-space-5);
  max-inline-size: 26rem;
}
</style>

Groupes et séparateurs

options accepte des options, des groupes nommés et des séparateurs. Le clavier passe par-dessus les groupes et les séparateurs.

vue
Europe
America
<script setup lang="ts">
import { ref } from 'vue'
import { VSelect, type SelectItem } from 'vectis-ui'

const country = ref('fr')

const items: SelectItem[] = [
  {
    label: 'Europe',
    options: [
      { value: 'fr', label: 'France' },
      { value: 'be', label: 'Belgium' },
      { value: 'ch', label: 'Switzerland' },
    ],
  },
  {
    label: 'America',
    options: [
      { value: 'ca', label: 'Canada' },
      { value: 'us', label: 'United States' },
      { value: 'br', label: 'Brazil' },
    ],
  },
  { separator: true },
  { value: 'other', label: 'Other' },
]
</script>

<template>
  <div class="column">
    <VSelect v-model="country" :options="items" label="Country" />
  </div>
</template>

<style scoped>
.column {
  max-inline-size: 26rem;
}
</style>

Sélection multiple

multiple utilise un tableau pour la sélection et affiche des chips amovibles. La liste reste ouverte pendant que l’on coche les options. max limite les valeurs visibles quand le champ n’a pas le focus.

vue
FranceBelgium+1

Two values are shown while the field is not focused

fr, be, ca
<script setup lang="ts">
import { ref } from 'vue'
import { VSelect } from 'vectis-ui'

const served = ref(['fr', 'be', 'ca'])

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'lu', label: 'Luxembourg' },
  { value: 'mc', label: 'Monaco', disabled: true },
  { value: 'ch', label: 'Switzerland' },
]
</script>

<template>
  <div class="column">
    <VSelect
      v-model="served"
      :options="countries"
      multiple
      clearable
      :max="2"
      label="Served countries"
      hint="Two values are shown while the field is not focused"
      placeholder="Choose countries"
    />
    <output class="value" aria-label="Chosen values">{{ served.join(', ') || 'none' }}</output>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-3);
  max-inline-size: 26rem;
}
.value {
  font-family: var(--vectis-text-family-code);
  font-size: var(--vectis-text-body-sm-size);
  color: var(--vectis-color-text-muted);
}
</style>

Valeurs en texte

display="text" réunit les libellés choisis sur une ligne, coupée par des points de suspension.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { VSelect } from 'vectis-ui'

const served = ref(['be', 'ca', 'fr', 'lu', 'ch'])

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'lu', label: 'Luxembourg' },
  { value: 'ch', label: 'Switzerland' },
]
</script>

<template>
  <div class="column">
    <VSelect
      v-model="served"
      :options="countries"
      multiple
      display="text"
      label="Served countries"
      placeholder="Choose countries"
    />
  </div>
</template>

<style scoped>
.column {
  max-inline-size: 20rem;
}
</style>

Options personnalisées

Utilisez #option pour personnaliser le contenu des options.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { VSelect } from 'vectis-ui'

const country = ref('fr')

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'lu', label: 'Luxembourg' },
  { value: 'ch', label: 'Switzerland' },
]

const capitals: Record<string, string> = {
  be: 'Brussels',
  ca: 'Ottawa',
  fr: 'Paris',
  lu: 'Luxembourg',
  ch: 'Bern',
}
</script>

<template>
  <div class="column">
    <VSelect v-model="country" :options="countries" label="Country">
      <template #option="{ option }">
        <span class="row">
          <span>{{ option.label }}</span>
          <small class="capital">{{ capitals[option.value] }}</small>
        </span>
      </template>
    </VSelect>
  </div>
</template>

<style scoped>
.column {
  max-inline-size: 26rem;
}
.row {
  display: grid;
}
.capital {
  color: var(--vectis-color-text-muted);
}
</style>

Formulaires

Un <select> natif masqué reçoit name, form, required et autocomplete. Le navigateur le valide à l’envoi, le remplissage automatique met à jour v-model, et la réinitialisation du formulaire rétablit la valeur initiale.

vue
nothing yet
<script setup lang="ts">
import { ref } from 'vue'
import { VButton, VSelect } from 'vectis-ui'

const country = ref('')
const submitted = ref('')

const countries = [
  { value: 'be', label: 'Belgium' },
  { value: 'ca', label: 'Canada' },
  { value: 'fr', label: 'France' },
  { value: 'ch', label: 'Switzerland' },
]

function onSubmit(event: Event) {
  const data = new FormData(event.target as HTMLFormElement)
  submitted.value = `country=${data.get('country')}`
}

function onReset() {
  submitted.value = ''
}
</script>

<template>
  <form class="column" @submit.prevent="onSubmit" @reset="onReset">
    <VSelect
      v-model="country"
      :options="countries"
      name="country"
      required
      label="Country"
      placeholder="Choose a country"
    />
    <div class="actions">
      <VButton type="submit">Submit</VButton>
      <VButton type="reset" variant="outline">Reset</VButton>
    </div>
    <output class="value" aria-label="Submitted data">{{ submitted || 'nothing yet' }}</output>
  </form>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-3);
  max-inline-size: 26rem;
}
.actions {
  display: flex;
  gap: var(--vectis-space-2);
}
.value {
  font-family: var(--vectis-text-family-code);
  font-size: var(--vectis-text-body-sm-size);
  color: var(--vectis-color-text-muted);
}
</style>

API

Props

PropTypeDéfaut
optionsSelectItem[]aucune
Options, groupes nommés ou séparateurs. Chaque option a une valeur et un libellé.
multiplebooleanfalse
Autorise la sélection multiple. Utilisez un tableau pour v-model. La liste reste ouverte pendant que l’on coche les options.
displaySelectDisplay'chip' | 'text''chip'
Affichage de la sélection multiple : chips amovibles ou texte séparé par des virgules. La sélection simple utilise toujours du texte.
maxnumberaucune
Nombre de valeurs visibles sans focus. Le focus affiche toutes les valeurs. Absent ou nul, tout est affiché. S’applique seulement avec multiple.
overflowText(count: number) => stringaucune
Formate le nombre de valeurs masquées par max. Reçoit le nombre masqué.
labelstringaucune
Label visible. Sans nom visible, fournissez aria-label ou aria-labelledby.
hintstringaucune
Texte d’aide lié par aria-describedby.
errorstringaucune
Message d’erreur affiché à la place du texte d’aide. Définit aria-invalid, est lié par aria-describedby et est annoncé à son apparition.
sizeSelectSize'sm' | 'md' | 'lg''md'
Taille du champ et des options. Le champ hérite d’une taille définie par VInputGroup.
compactbooleanfalse
Réduit la hauteur du contrôle sans changer le texte ni les icônes.
placeholderstringaucune
Texte affiché tant que rien n’est choisi.
disabledbooleanfalse
Désactive l’interaction. La valeur n’est pas envoyée.
readonlybooleanfalse
Empêche de changer la sélection. Conserve le focus et l’envoi ; masque les actions d’effacement et empêche d’ouvrir la liste.
invalidbooleanfalse
Définit aria-invalid et le style d’erreur. Ne bloque pas l’envoi du formulaire à lui seul.
iconStartIconSourceaucune
Icône de début, avant les valeurs choisies. Un écouteur @click:icon-start en fait un bouton qui exige iconStartLabel.
iconStartLabelstringaucune
Nom accessible du bouton d’icône de début.
expandIconIconSourceexpand_more
Chevron décoratif, tourné pendant que la liste est ouverte.
clearablebooleanfalse
Ajoute une action pour effacer la sélection.
clearLabelstringaucune
Nom accessible du bouton d’effacement. Par défaut, celui du dictionnaire.
placementSelectPlacement'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end''bottom-start'
Position préférée du panneau par rapport au champ.
v-modelItemValue | ItemValue[]''
Chaîne ou nombre choisi, ou tableau avec multiple. Une chaîne vide par défaut.

Événements

ÉvénementType
click:icon-start[event: MouseEvent]
Émis à l’activation du bouton d’icône de début.
clear[]
Émis après l’effacement de la sélection.

Slots

SlotType
start{}
Contenu après iconStart et les chips, sans les remplacer.
value-end{}
Contenu avant l’action d’effacement et l’icône d’ouverture.
optionListboxOptionSlotProps
Contenu d’une option. Reçoit l’option, l’index, l’état actif et l’état choisi.
chipListboxChipSlotProps
Chip d’une valeur choisie. Reçoit la valeur, le libellé, l’option éventuelle, remove, la taille et l’état compact. Branchez l’action de retrait.
overflowListboxOverflowSlotProps
Nombre de valeurs masquées. Reçoit count, la taille des chips et l’état compact.

Types

Types utilisés dans les tables d’API. Importez les types exportés depuis vectis-ui.

export interface BuiltinIcon {
  name: string
  paths: readonly [string] | readonly [string, string]
}
export type ChipSize = 'xs' | 'sm'
export type IconRender =
  | { path: string; viewBox?: string }
  | { component: Component; props?: Record<string, unknown> }
  | { src: string }
  | { text: string; class?: string }
  | { class: string }
export type IconSource = string | BuiltinIcon | IconRender
export type ItemValue = string | number
export interface ListboxChipSlotProps {
  value: ItemValue
  option: ListboxOption | undefined
  label: string
  remove: () => void
  size: ChipSize
  compact: boolean
}
export interface ListboxGroup {
  label: string
  options: ListboxOption[]
}
export type ListboxItem = ListboxOption | ListboxGroup | ListboxSeparator
export interface ListboxOption {
  value: ItemValue
  label: string
  icon?: IconSource
  disabled?: boolean
}
export interface ListboxOptionSlotProps {
  option: ListboxOption
  index: number
  active: boolean
  selected: boolean
}
export interface ListboxOverflowSlotProps {
  count: number
  size: ChipSize
  compact: boolean
}
export interface ListboxSeparator {
  separator: true
}
export type SelectItem = ListboxItem

Variables CSS

TokenValeur
--vectis-control-size-select-list-max-block18rem