Skip to content

SelectBoxField

Composant SelectBoxField personnalisé avec support de la sélection multiple, recherche intégrée, groupes d'options et accessibilité complète selon les normes W3C.

Exemples d'utilisation

SelectBoxField de base

SelectBox simple

vue
<script setup>
const selectedValue = ref('')
const options = [
  { value: 'option1', label: 'Option 1' },
  { value: 'option2', label: 'Option 2' },
  { value: 'option3', label: 'Option 3' },
  { value: 'option4', label: 'Option 4', disabled: true }
]
</script>

<template>
  <SuSelectBoxField 
    :options="options"
    label="Sélection simple"
    placeholder="Choisissez une option..."
    v-model:value="selectedValue"
  />
</template>

Sélection multiple

Sélection multiple avec tags

vue
<script setup>
const selectedTechnologies = ref([])
const technologies = [
  { value: 'js', label: 'JavaScript' },
  { value: 'ts', label: 'TypeScript' },
  { value: 'vue', label: 'Vue.js' },
  { value: 'react', label: 'React' },
  { value: 'angular', label: 'Angular' }
]
</script>

<template>
  <SuSelectBoxField 
    :options="technologies"
    :multiple="true"
    :clearable="true"
    label="Technologies"
    placeholder="Sélectionnez vos technologies..."
    helpText="Vous pouvez sélectionner plusieurs options"
    v-model:value="selectedTechnologies"
  />
</template>

Recherche intégrée

SelectBox avec recherche

vue
<script setup>
const selectedCountry = ref('')
const countries = [
  { value: 'fr', label: 'France' },
  { value: 'us', label: 'États-Unis' },
  { value: 'de', label: 'Allemagne' },
  { value: 'es', label: 'Espagne' },
  { value: 'it', label: 'Italie' },
  { value: 'uk', label: 'Royaume-Uni' },
  { value: 'ca', label: 'Canada' },
  { value: 'jp', label: 'Japon' }
]
</script>

<template>
  <SuSelectBoxField 
    :options="countries"
    :searchable="true"
    :clearable="true"
    label="Pays"
    placeholder="Rechercher un pays..."
    searchPlaceholder="Tapez pour rechercher..."
    v-model:value="selectedCountry"
  />
</template>

Options avec icônes et descriptions

Options enrichies

vue
<script setup>
import { ref } from 'vue'
import { StarIcon, BuildingOfficeIcon, GlobeAltIcon } from '@heroicons/vue/24/outline'

const selectedPlan = ref('')
const plans = [
  { 
    value: 'basic', 
    label: 'Plan Basic', 
    description: 'Fonctionnalités de base pour débuter',
    icon: StarIcon 
  },
  { 
    value: 'pro', 
    label: 'Plan Pro', 
    description: 'Fonctionnalités avancées pour les professionnels',
    icon: BuildingOfficeIcon 
  },
  { 
    value: 'enterprise', 
    label: 'Plan Enterprise', 
    description: 'Solution complète pour les grandes entreprises',
    icon: GlobeAltIcon 
  }
]
</script>

<template>
  <SuSelectBoxField 
    :options="plans"
    :searchable="true"
    label="Plan d'abonnement"
    placeholder="Choisissez votre plan..."
    v-model:value="selectedPlan"
  />
</template>

Options groupées

Options organisées en groupes

vue
<template>
  <SuSelectBoxField 
    :groups="[
      {
        label: 'Fruits',
        options: [
          { value: 'apple', label: 'Pomme' },
          { value: 'banana', label: 'Banane' },
          { value: 'orange', label: 'Orange' }
        ]
      },
      {
        label: 'Légumes',
        options: [
          { value: 'carrot', label: 'Carotte' },
          { value: 'broccoli', label: 'Brocoli' },
          { value: 'spinach', label: 'Épinard' }
        ]
      }
    ]"
    :searchable="true"
    :multiple="true"
    label="Produits alimentaires"
    placeholder="Sélectionnez des produits..."
    v-model:value="selectedProducts"
  />
</template>

Tailles

Tailles disponibles

vue
<template>
  <SuSelectBoxField size="sm" label="Small" placeholder="Petit SelectBox" />
  <SuSelectBoxField size="md" label="Medium" placeholder="SelectBox moyen" />
  <SuSelectBoxField size="lg" label="Large" placeholder="Grand SelectBox" />
</template>

États et validation

États de validation

vue
<template>
  <SuSelectBoxField 
    state="default"
    label="État par défaut"
    message="Texte d'aide pour guider l'utilisateur"
  />
  <SuSelectBoxField 
    state="error"
    label="État d'erreur"
    message="Cette sélection contient une erreur"
  />
  <SuSelectBoxField 
    state="success"
    label="État de succès"
    message="Sélection valide !"
  />
  <SuSelectBoxField 
    state="warning"
    label="État d'avertissement"
    message="Attention à cette sélection"
  />
</template>

Support RTL et alignement

Support des langues RTL

vue
<template>
  <!-- Support RTL -->
  <SuSelectBoxField 
    :options="rtlOptions"
    dir="rtl"
    label="اللغة (RTL)"
    placeholder="اختر لغة..."
  />
  
  <!-- Alignement personnalisé -->
  <SuSelectBoxField 
    :options="options"
    textAlign="center"
    label="Alignement centré"
    placeholder="Texte centré"
  />
</template>

API

Props

PropTypeDefaultDescription
optionsSelectOption[][]Liste des options disponibles
groupsSelectGroup[][]Options organisées en groupes
valuestring | number | (string | number)[]undefinedValeur sélectionnée
multiplebooleanfalseSélection multiple
searchablebooleanfalseRecherche intégrée
clearablebooleanfalseBouton d'effacement
size'sm' | 'md' | 'lg''md'Taille du SelectBox
state'default' | 'error' | 'success' | 'warning''default'État visuel
disabledbooleanfalseDésactive le SelectBox
readonlybooleanfalseSelectBox en lecture seule
requiredbooleanfalseChamp requis
placeholderstring'Sélectionnez une option...'Texte de placeholder
searchPlaceholderstring'Rechercher...'Placeholder de recherche
noOptionsTextstring'Aucune option disponible'Texte sans options
noResultsTextstring'Aucun résultat trouvé'Texte sans résultats
maxHeightstring'200px'Hauteur max du dropdown
textAlign'left' | 'center' | 'right''left'Alignement du texte
dir'ltr' | 'rtl' | 'auto''auto'Direction du texte
loadingbooleanfalseÉtat de chargement
closeOnSelectbooleantrueFermer après sélection
maxSelectedItemsnumberundefinedLimite de sélection multiple
labelstringundefinedLabel du SelectBox
messagestringundefinedMessage affiché (style déterminé par le state)

Types d'options

SelectOption

typescript
interface SelectOption {
  value: string | number
  label: string
  disabled?: boolean
  group?: string
  icon?: Component
  description?: string
}

SelectGroup

typescript
interface SelectGroup {
  label: string
  options: SelectOption[]
}

Events

EventTypeDescription
@update:value(value: string | number | (string | number)[]) => voidÉmis lors du changement de valeur
@change(value: string | number | (string | number)[]) => voidÉmis lors du changement
@open() => voidÉmis à l'ouverture du dropdown
@close() => voidÉmis à la fermeture du dropdown
@search(query: string) => voidÉmis lors de la recherche
@focus(event: FocusEvent) => voidÉmis lors du focus
@blur(event: FocusEvent) => voidÉmis lors de la perte de focus

Méthodes exposées

MéthodeTypeDescription
focus()() => voidDonne le focus au SelectBox
open()() => voidOuvre le dropdown
close()() => voidFerme le dropdown
selectRefRef<HTMLDivElement>Référence au conteneur
inputRefRef<HTMLInputElement>Référence au trigger

Accessibilité

Le composant SelectBox respecte les normes WCAG 2.1 AA et les bonnes pratiques W3C :

✅ Fonctionnalités d'accessibilité

  • Navigation au clavier : Support complet des touches fléchées, Entrée, Espace, Échap, Home/End
  • Attributs ARIA : role="combobox", aria-expanded, aria-controls, aria-multiselectable
  • Focus trap : Gestion du focus dans le dropdown ouvert
  • Annonces vocales : Messages pour les lecteurs d'écran lors des sélections
  • Labels associés : Chaque SelectBox a un label correctement associé
  • Messages d'état : Messages d'erreur/succès/avertissement avec aria-live
  • Contraste des couleurs : Ratios conformes WCAG AA (4.5:1 minimum)
  • Focus visible : Indicateurs de focus clairs et contrastés
  • Support RTL : Gestion complète des langues de droite à gauche
  • Mode sombre : Contraste adapté automatiquement
  • Contraste élevé : Support de prefers-contrast: high
  • Réduction d'animation : Respect de prefers-reduced-motion

🎯 Bonnes pratiques

vue
<!-- SelectBox avec validation et accessibilité -->
<SuSelectBoxField 
  :options="options"
  :required="true"
  label="Catégorie"
  placeholder="Sélectionnez une catégorie..."
  :state="hasError ? 'error' : 'default'"
  :message="hasError ? 'Veuillez sélectionner une catégorie' : 'Choisissez la catégorie qui correspond le mieux'"
  v-model:value="category"
/>

<!-- SelectBox multiple avec limite -->
<SuSelectBoxField 
  :options="skills"
  :multiple="true"
  :maxSelectedItems="5"
  :searchable="true"
  :clearable="true"
  label="Compétences"
  placeholder="Sélectionnez vos compétences..."
  message="Maximum 5 compétences"
  v-model:value="selectedSkills"
/>

<!-- SelectBox avec groupes et recherche -->
<SuSelectBoxField 
  :groups="categorizedOptions"
  :searchable="true"
  label="Produit"
  placeholder="Rechercher un produit..."
  searchPlaceholder="Tapez pour filtrer..."
  ariaLabel="Sélecteur de produits par catégorie"
  v-model:value="selectedProduct"
/>
ToucheAction
TabNaviguer vers/depuis le SelectBox
Entrée / EspaceOuvrir/fermer le dropdown, sélectionner l'option focalisée
Flèche basOuvrir le dropdown ou naviguer vers l'option suivante
Flèche hautNaviguer vers l'option précédente
HomeAller à la première option
EndAller à la dernière option
ÉchapFermer le dropdown
A-ZRecherche rapide par première lettre (si pas de recherche intégrée)

Exemples d'usage avancés

Formulaire de profil utilisateur

vue
<script setup>
import { ref } from 'vue'
import { UserIcon, BuildingOfficeIcon, GlobeAltIcon } from '@heroicons/vue/24/outline'

const userType = ref('')
const skills = ref([])
const country = ref('')

const userTypes = [
  { value: 'individual', label: 'Particulier', icon: UserIcon },
  { value: 'business', label: 'Entreprise', icon: BuildingOfficeIcon },
  { value: 'organization', label: 'Organisation', icon: GlobeAltIcon }
]

const skillOptions = [
  { value: 'js', label: 'JavaScript', group: 'Frontend' },
  { value: 'ts', label: 'TypeScript', group: 'Frontend' },
  { value: 'vue', label: 'Vue.js', group: 'Frontend' },
  { value: 'node', label: 'Node.js', group: 'Backend' },
  { value: 'python', label: 'Python', group: 'Backend' },
  { value: 'docker', label: 'Docker', group: 'DevOps' }
]

const countries = [
  { value: 'fr', label: 'France' },
  { value: 'us', label: 'États-Unis' },
  { value: 'de', label: 'Allemagne' }
]
</script>

<template>
  <form class="space-y-6">
    <SuSelectBoxField 
      :options="userTypes"
      :required="true"
      label="Type d'utilisateur"
      placeholder="Sélectionnez votre type..."
      v-model:value="userType"
    />
    
    <SuSelectBoxField 
      :options="skillOptions"
      :multiple="true"
      :searchable="true"
      :clearable="true"
      :maxSelectedItems="3"
      label="Compétences"
      placeholder="Sélectionnez vos compétences..."
      helpText="Maximum 3 compétences"
      v-model:value="skills"
    />
    
    <SuSelectBoxField 
      :options="countries"
      :searchable="true"
      :clearable="true"
      label="Pays"
      placeholder="Rechercher votre pays..."
      v-model:value="country"
    />
  </form>
</template>

SelectBox avec chargement dynamique

vue
<script setup>
import { ref, watch } from 'vue'

const searchQuery = ref('')
const options = ref([])
const loading = ref(false)
const selectedValue = ref('')

const searchOptions = async (query) => {
  loading.value = true
  try {
    // Simulation d'une API
    const response = await fetch(`/api/search?q=${query}`)
    options.value = await response.json()
  } finally {
    loading.value = false
  }
}

watch(searchQuery, (newQuery) => {
  if (newQuery.length > 2) {
    searchOptions(newQuery)
  }
})
</script>

<template>
  <SuSelectBoxField 
    :options="options"
    :searchable="true"
    :loading="loading"
    label="Recherche dynamique"
    placeholder="Tapez pour rechercher..."
    searchPlaceholder="Minimum 3 caractères..."
    @search="searchQuery = $event"
    v-model:value="selectedValue"
  />
</template>

Publié sous licence MIT.