Skip to content

Input

Composant input flexible avec support complet des types HTML, préfixes/suffixes, alignement de texte, direction RTL/LTR et accessibilité selon les normes W3C.

Description

SuInput est un composant de champ de saisie enrichi qui étend les capacités de l'élément HTML <input> natif. Il offre un support avancé pour les préfixes/suffixes textuels et iconographiques, l'alignement du texte, et la gestion complète de l'accessibilité.

Exemples d'utilisation

Usage basique

champs de texte simple

vue
<template>
  <SuInput type="text" placeholder="Entrez du texte" />
</template>

Avec FormField

Types d'input supportés

vue
<template>
  <SuFormField label="Nom d'utilisateur">
    <SuInput placeholder="Entrez votre nom" />
  </SuFormField>
</template>

En savoir plus sur l’utilisation de SuFormField.

Types d'input

Types d'input supportés

vue
<template>
  <SuFormField label="Texte" >
    <SuInput type="text" placeholder="Entrez du texte" />
  </SuFormField>
  <SuFormField label="email" >
    <SuInput type="email" placeholder="nom@exemple.com" />
  </SuFormField>
  <SuFormField label="password" >
    <SuInput type="password" placeholder="••••••••" />
  </SuFormField>
  <SuFormField label="number" >
    <SuInput type="number" placeholder="123" />
  </SuFormField>
  <SuFormField label="Tél" >
    <SuInput type="tel" placeholder="+33 1 23 45 67 89" />
  </SuFormField>
  <SuFormField label="Url" >
    <SuInput type="url" placeholder="https://exemple.com" />
  </SuFormField>
  <SuFormField label="Recherche" >
    <SuInput type="search" placeholder="Rechercher..." />
  </SuFormField>
  <SuFormField label="Date" >
    <SuInput type="date" />
  </SuFormField>
</template>

Préfixes et suffixes

Préfixes et suffixes texte

vue
<template>
  <SuFormField label="Prix" >
    <SuInput placeholder="0.00" suffix="€" text-align="right" type="number" />
  </SuFormField>
  <SuFormField label="Email" >
    <SuInput placeholder="nom" suffix="@entreprise.com" />
  </SuFormField>
  <SuFormField label="Site web" >
    <SuInput placeholder="monsite" prefix="https://" suffix=".com" />
  </SuFormField>
  <SuFormField label="Téléphone" >
    <SuInput placeholder="123456789" prefix="+33" />
  </SuFormField>
</template>

Préfixes et suffixes avec icônes

Préfixes et suffixes avec icônes

vue
<script setup>
import { 
  MagnifyingGlassIcon, 
  AtSymbolIcon, 
  LockClosedIcon, 
  UserIcon 
} from '@heroicons/vue/24/outline'
</script>

<template>
  <SuFormField label="Recherche" >
    <SuInput placeholder="Rechercher..." :prefixIcon="MagnifyingGlassIcon" />
  </SuFormField>
  <SuFormField label="Email" >
    <SuInput placeholder="votre@email.com" :prefixIcon="AtSymbolIcon" />
  </SuFormField>
  <SuFormField label="Mot de passe" >
    <SuInput placeholder="••••••••" type="password" :prefixIcon="LockClosedIcon" />
  </SuFormField>
  <SuFormField label="Utilisateur" >
    <SuInput placeholder="Nom d'utilisateur" :prefixIcon="UserIcon" />
  </SuFormField>
</template>

Tailles

Tailles disponibles

vue
<template>
  <SuFormField label="Small" >
    <SuInput size="sm" placeholder="Petit input" />
  </SuFormField>
  <SuFormField label="Medium" >
    <SuInput size="md" placeholder="Input moyen" />
  </SuFormField>
  <SuFormField label="Large" >
    <SuInput size="lg" placeholder="Grand input" />
  </SuFormField>
</template>

États de validation

États de validation

vue
<template>
  <SuFormField 
    label="État par défaut" 
    message="Texte d'aide pour guider l'utilisateur"
  >
    <SuInput placeholder="Entrez du texte" />
  </SuFormField>
  
  <SuFormField 
    state="error"
    label="État d'erreur" 
    message="Ce champ contient une erreur"
  >
    <SuInput value="valeur incorrecte" />
  </SuFormField>
  
  <SuFormField 
    state="success"
    label="État de succès" 
    message="Valeur valide !"
  >
    <SuInput value="valeur correcte" />
  </SuFormField>
  
  <SuFormField 
    state="warning"
    label="État d'avertissement" 
    message="Attention à cette valeur"
  >
    <SuInput value="attention" />
  </SuFormField>
</template>

Alignement du texte

Alignement du texte

vue
<template>
  <SuFormField label="Alignement à gauche" >
    <SuInput textAlign="left" value="Aligné à gauche" />
  </SuFormField>
  <SuFormField label="Alignement centré" >
    <SuInput textAlign="center" value="Centré" />
  </SuFormField>
  <SuFormField label="Alignement à droite" >
    <SuInput textAlign="right" value="Aligné à droite" />
  </SuFormField>
</template>

Support RTL (droite à gauche)

Support des langues RTL

vue
<template>
  <div dir="rtl">
    <SuFormField label="Texte arabe (RTL)" >
      <SuInput 
        placeholder="أدخل النص هنا"
        value="النص العربي"
      />
    </SuFormField>
    <SuFormField label="Texte hébreu (RTL)">
      <SuInput 
        placeholder="הכנס טקסט כאן"
        value="טקסט עברי"
      />
    </SuFormField>
    <SuFormField label="Prix (RTL avec suffixe)" >
      <SuInput 
        placeholder="0.00"
        suffix="$"
        type="number"
      />
    </SuFormField>
  </div>
</template>

États disabled et readonly

États spéciaux

vue
<template>
  <SuFormField label="Input désactivé" :disabled="true">
    <SuInput 
      :disabled="true"
      value="Valeur désactivée"
    />
  </SuFormField>
  <SuFormField label="Input en lecture seule">
    <SuInput 
      :readonly="true"
      value="Valeur en lecture seule"
    />
  </SuFormField>
  <SuFormField label="Champ requis" :required="true">
    <SuInput 
      :required="true"
      placeholder="Ce champ est obligatoire"
    />
  </SuFormField>
</template>

API

Props

PropTypeDefaultDescription
typeInputType'text'Type d'input HTML
size'sm' | 'md' | 'lg''md'Taille de l'input
state'default' | 'error' | 'success' | 'warning''default'État visuel de l'input
disabledbooleanfalseDésactive l'input
readonlybooleanfalseInput en lecture seule
requiredbooleanfalseChamp requis
placeholderstringundefinedTexte de placeholder
valuestring | numberundefinedValeur de l'input
modelValuestring | numberundefinedValeur v-model
prefixstringundefinedPréfixe texte
suffixstringundefinedSuffixe texte
prefixIconComponentundefinedIcône de préfixe (composant Heroicons)
suffixIconComponentundefinedIcône de suffixe (composant Heroicons)
textAlign'left' | 'center' | 'right''left'Alignement du texte

Attributs d'accessibilité

PropTypeDefaultDescription
ariaLabelstringundefinedLabel accessible pour lecteurs d'écran
ariaDescribedBystringundefinedID de l'élément de description
ariaInvalidbooleanundefinedIndique si la valeur est invalide
ariaRequiredbooleanundefinedIndique si le champ est requis

Attributs de validation HTML

PropTypeDefaultDescription
autocompletestringundefinedAttribut autocomplete HTML
minnumber | stringundefinedValeur minimale (type number, date, etc.)
maxnumber | stringundefinedValeur maximale (type number, date, etc.)
stepnumber | stringundefinedPas pour les nombres
minLengthnumberundefinedLongueur minimale du texte
maxLengthnumberundefinedLongueur maximale du texte
patternstringundefinedExpression régulière de validation

Events

EventTypeDescription
@update:modelValue(value: string | number) => voidÉmis lors du changement de valeur (v-model)
@input(event: Event) => voidÉmis lors de la saisie
@change(event: Event) => voidÉmis lors du changement
@focus(event: FocusEvent) => voidÉmis lors du focus
@blur(event: FocusEvent) => voidÉmis lors de la perte de focus
@keydown(event: KeyboardEvent) => voidÉmis lors de l'appui sur une touche
@keyup(event: KeyboardEvent) => voidÉmis lors du relâchement d'une touche

Méthodes exposées

MéthodeTypeDescription
focus()() => voidDonne le focus à l'input
select()() => voidSélectionne le texte de l'input
blur()() => voidRetire le focus de l'input
inputRefRef<HTMLInputElement>Référence à l'élément input natif

Accessibilité

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

✅ Fonctionnalités d'accessibilité

  • Attributs ARIA : Support complet des attributs ARIA (aria-label, aria-describedby, aria-invalid, etc.)
  • Contraste des couleurs : Ratios de contraste conformes WCAG AA (4.5:1 minimum)
  • Focus visible : Indicateur de focus clair et contrasté avec outline
  • Tailles minimales : Respecte les tailles minimales de cible tactile (44x44px minimum)
  • Support RTL : Gestion automatique des langues de droite à gauche
  • Mode sombre : Contraste adapté en mode sombre
  • Contraste élevé : Support de prefers-contrast: high
  • Réduction d'animation : Respect de prefers-reduced-motion
  • États clairs : États visuels distincts pour erreur, succès, avertissement

🎯 Bonnes pratiques

vue
<!-- Input avec validation et accessibilité -->
<SuInput 
  type="email"
  placeholder="nom@exemple.com"
  :required="true"
  autocomplete="email"
  ariaLabel="Adresse email"
  ariaDescribedBy="email-help"
  v-model="email"
/>

<!-- Input avec gestion d'erreur -->
<SuInput 
  type="password"
  placeholder="••••••••"
  :required="true"
  :state="hasError ? 'error' : 'default'"
  :ariaInvalid="hasError"
  :minLength="8"
  autocomplete="new-password"
  v-model="password"
/>

<!-- Input avec préfixe et validation numérique -->
<SuInput 
  type="number"
  :required="true"
  :min="0"
  :max="120"
  placeholder="Âge"
  ariaLabel="Votre âge en années"
  v-model="age"
/>

Types supportés

Le composant Input supporte tous les types d'input HTML5 :

  • text - Texte libre
  • email - Adresse email avec validation
  • password - Mot de passe masqué
  • number - Nombre avec contrôles
  • tel - Numéro de téléphone
  • url - URL avec validation
  • search - Champ de recherche
  • date - Sélecteur de date
  • time - Sélecteur d'heure
  • datetime-local - Date et heure locales
  • month - Sélecteur de mois
  • week - Sélecteur de semaine
  • color - Sélecteur de couleur
  • file - Sélection de fichier

Exemples d'usage avancés

Input de recherche avec icône

vue
<script setup>
import { ref } from 'vue'
import { MagnifyingGlassIcon } from '@heroicons/vue/24/outline'

const searchQuery = ref('')

const handleSearch = () => {
  console.log('Recherche:', searchQuery.value)
}
</script>

<template>
  <SuInput 
    type="search"
    placeholder="Rechercher..."
    :prefixIcon="MagnifyingGlassIcon"
    v-model="searchQuery"
    @keyup.enter="handleSearch"
  />
</template>

Champ de prix avec formatage

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

const price = ref('')

const formattedPrice = computed({
  get: () => price.value,
  set: (value) => {
    const numericValue = value.replace(/[^\d.,]/g, '')
    price.value = numericValue
  }
})
</script>

<template>
  <SuInput 
    type="number"
    suffix="€"
    placeholder="0.00"
    :step="0.01"
    :min="0"
    textAlign="right"
    v-model="formattedPrice"
  />
</template>

Input avec validation en temps réel

vue
<script setup>
import { ref, computed } from 'vue'
import { AtSymbolIcon } from '@heroicons/vue/24/outline'

const email = ref('')

const emailState = computed(() => {
  if (!email.value) return 'default'
  const isValid = /\S+@\S+\.\S+/.test(email.value)
  return isValid ? 'success' : 'error'
})
</script>

<template>
  <SuInput 
    type="email"
    :prefixIcon="AtSymbolIcon"
    placeholder="nom@exemple.com"
    :state="emailState"
    autocomplete="email"
    v-model="email"
  />
</template>

Input de téléphone international

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

const phoneNumber = ref('')
const countryCode = ref('+33')
</script>

<template>
  <SuInput 
    type="tel"
    :prefix="countryCode"
    placeholder="6 12 34 56 78"
    autocomplete="tel"
    v-model="phoneNumber"
  />
</template>

Input avec actions de suffixe

vue
<script setup>
import { ref } from 'vue'
import { EyeIcon, EyeSlashIcon } from '@heroicons/vue/24/outline'

const password = ref('')
const showPassword = ref(false)

const togglePasswordVisibility = () => {
  showPassword.value = !showPassword.value
}
</script>

<template>
  <div class="relative">
    <SuInput 
      :type="showPassword ? 'text' : 'password'"
      placeholder="••••••••"
      autocomplete="current-password"
      v-model="password"
    />
    <button 
      type="button"
      class="absolute right-3 top-1/2 -translate-y-1/2"
      @click="togglePasswordVisibility"
      aria-label="Afficher/masquer le mot de passe"
    >
      <component :is="showPassword ? EyeSlashIcon : EyeIcon" class="w-5 h-5" />
    </button>
  </div>
</template>

Utilisation avec SuFormField

Pour une expérience complète avec label, message et validation, utilisez SuInput avec SuFormField :

vue
<template>
  <SuFormField 
    label="Email"
    :required="true"
    :state="emailError ? 'error' : 'default'"
    :message="emailError || 'Utilisé pour la connexion'"
  >
    <SuInput 
      type="email"
      placeholder="nom@exemple.com"
      :prefixIcon="AtSymbolIcon"
      autocomplete="email"
      v-model="email"
    />
  </SuFormField>
</template>

Notes d'implémentation

  • Le composant gère automatiquement la direction du texte (LTR/RTL) en fonction du contexte
  • Les préfixes et suffixes sont positionnés de manière responsive
  • Les icônes sont automatiquement dimensionnées selon la taille de l'input
  • Le focus ring est toujours visible pour l'accessibilité au clavier
  • Les états de validation sont communiqués visuellement et via ARIA

Publié sous licence MIT.