Skip to content

SuSlider

Composant SuSlider pour la sélection de valeurs numériques avec support du dual-range automatique, orientation verticale/horizontale, tooltips, marques personnalisées et accessibilité complète selon les normes W3C.

Utilisation simple

Le composant SuSlider peut être utilisé de manière autonome sans le wrapper SuFormField.

Slider de base

Slider simple

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

const volume = ref(50)
</script>

<template>
  <SuSlider 
    :min="0"
    :max="100"
    v-model="volume"
  />
</template>

Dual-range (plage de valeurs)

Sélection d'une plage

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

const priceRange = ref([200, 800])
const formatPrice = (value) => `${value}€`
</script>

<template>
  <SuSlider 
    :min="0"
    :max="1000"
    :step="10"
    :showValue="true"
    :formatValue="formatPrice"
    v-model="priceRange"
  />
</template>

Utilisation avec SuFormField

Pour une meilleure structuration des formulaires, utilisez SuSlider avec le composant SuFormField.

Slider avec label et message

Slider dans un formulaire

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

const volume = ref(50)
</script>

<template>
  <SuFormField 
    label="Volume"
    message="Ajustez le volume"
  >
    <SuSlider 
      :min="0"
      :max="100"
      :showValue="true"
      v-model="volume"
    />
  </SuFormField>
</template>

Dual-range avec validation

Fourchette de prix avec validation

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

const priceRange = ref([200, 800])

const formatPrice = (value) => `${value}€`

const budgetState = computed(() => {
  const [min, max] = priceRange.value
  if (max - min < 100) return 'error'
  if (max - min > 500) return 'success'
  return 'default'
})

const budgetMessage = computed(() => {
  const [min, max] = priceRange.value
  if (max - min < 100) return 'La plage doit être d\'au moins 100€'
  if (max - min > 500) return 'Budget défini avec succès'
  return 'Définissez votre budget'
})
</script>

<template>
  <SuFormField 
    label="Fourchette de prix"
    :state="budgetState"
    :message="budgetMessage"
    required
  >
    <SuSlider 
      :min="0"
      :max="1000"
      :step="10"
      :showValue="true"
      :showLabels="true"
      :formatValue="formatPrice"
      v-model="priceRange"
    />
  </SuFormField>
</template>

Avec tooltips

Tooltips au survol

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

const volume = ref(60)
const range = ref([30, 70])
</script>

<template>
  <SuFormField 
    label="Volume avec tooltip"
    message="Survolez le curseur pour voir la valeur"
  >
    <SuSlider 
      :min="0"
      :max="100"
      tooltip="top"
      v-model="volume"
    />
  </SuFormField>
  
  <SuFormField 
    label="Plage avec tooltips"
    message="Tooltips en bas"
  >
    <SuSlider 
      :min="0"
      :max="100"
      tooltip="bottom"
      v-model="range"
    />
  </SuFormField>
</template>

Avec marques personnalisées

Marques sur le slider

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

const difficulty = ref(60)

const formatDifficulty = (value) => {
  if (value === 0) return 'Facile'
  if (value === 25) return 'Moyen'
  if (value === 50) return 'Difficile'
  if (value === 75) return 'Expert'
  if (value === 100) return 'Maître'
  return value.toString()
}
</script>

<template>
  <SuFormField 
    label="Niveau de difficulté"
  >
    <SuSlider 
      :min="0"
      :max="100"
      :marks="[0, 25, 50, 75, 100]"
      tooltip="top"
      :formatValue="formatDifficulty"
      v-model="difficulty"
    />
  </SuFormField>
</template>

Avec graduations et labels

Slider avec graduations

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

const rating = ref(7)
</script>

<template>
  <SuFormField 
    label="Note"
    message="Donnez une note de 0 à 10"
  >
    <SuSlider 
      :min="0"
      :max="10"
      :step="1"
      :showValue="true"
      :showTicks="true"
      :showLabels="true"
      v-model="rating"
    />
  </SuFormField>
</template>

Orientation verticale

Slider vertical

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

const verticalVolume = ref(75)
</script>

<template>
  <SuFormField 
    label="Volume vertical"
    message="Contrôle vertical du volume"
  >
    <SuSlider 
      :min="0"
      :max="100"
      orientation="vertical"
      tooltip="top"
      :showLabels="true"
      v-model="verticalVolume"
    />
  </SuFormField>
</template>

Avec slots before et after

Slider avec contenu personnalisé

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

const volume = ref(60)
</script>

<template>
  <SuFormField 
    label="Volume avec contrôles"
  >
    <SuSlider 
      :min="0"
      :max="100"
      tooltip="top"
      v-model="volume"
    >
      <template #before>
        <div class="volume-icons">
          <span>🔇</span>
          <span>Silencieux</span>
        </div>
      </template>
      <template #after>
        <div class="volume-icons">
          <span>Fort</span>
          <span>🔊</span>
        </div>
      </template>
    </SuSlider>
  </SuFormField>
</template>

États de validation

États de formulaire

vue
<template>
  <SuFormField 
    label="État par défaut"
    message="Message d'aide normal"
    state="default"
  >
    <SuSlider :min="0" :max="100" :value="50" />
  </SuFormField>
  
  <SuFormField 
    label="État d'erreur"
    message="La valeur doit être supérieure à 30"
    state="error"
    required
  >
    <SuSlider :min="0" :max="100" :value="20" />
  </SuFormField>
  
  <SuFormField 
    label="État de succès"
    message="Valeur validée avec succès"
    state="success"
  >
    <SuSlider :min="0" :max="100" :value="80" />
  </SuFormField>
  
  <SuFormField 
    label="État d'avertissement"
    message="Attention, valeur proche du maximum"
    state="warning"
  >
    <SuSlider :min="0" :max="100" :value="95" />
  </SuFormField>
</template>

Support RTL

Support des langues RTL

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

const volume = ref(70)
</script>

<template>
  <SuFormField 
    label="مستوى الصوت (RTL)"
    dir="rtl"
  >
    <SuSlider 
      :min="0"
      :max="100"
      dir="rtl"
      tooltip="top"
      :showLabels="true"
      :formatValue="(value) => value + '%'"
      v-model="volume"
    />
  </SuFormField>
</template>

Utilisation avec SuSliderField

Pour plus de simplicité, vous pouvez également utiliser le composant SuSliderField qui regroupe SuFormField et SuSlider en un seul composant :

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

const volume = ref(50)
</script>

<template>
  <SuSliderField 
    label="Volume"
    :min="0"
    :max="100"
    :showValue="true"
    message="Ajustez le volume"
    v-model="volume"
  />
</template>

Cette approche est équivalente à :

vue
<SuFormField 
  label="Volume"
  message="Ajustez le volume"
>
  <SuSlider 
    :min="0"
    :max="100"
    :showValue="true"
    v-model="volume"
  />
</SuFormField>

API

Props

PropTypeDefaultDescription
valuenumber | [number, number]minValeur du slider (nombre simple ou tableau pour dual-range)
minnumber0Valeur minimale
maxnumber100Valeur maximale
stepnumber1Pas d'incrémentation
size'sm' | 'md' | 'lg''md'Taille du slider
disabledbooleanfalseDésactive le slider
readonlybooleanfalseSlider en lecture seule
orientation'horizontal' | 'vertical''horizontal'Orientation du slider
tooltip'none' | 'top' | 'bottom''none'Position du tooltip au survol
marksnumber[][]Marques à afficher sur le slider
showValuebooleantrueAfficher la valeur courante
showTicksbooleanfalseAfficher les graduations
showLabelsbooleanfalseAfficher les labels min/max
formatValue(value: number) => stringundefinedFonction de formatage des valeurs
dir'ltr' | 'rtl' | 'auto''auto'Direction du texte

Attributs d'accessibilité

PropTypeDefaultDescription
ariaLabelstringundefinedLabel accessible
ariaDescribedBystringundefinedID de l'élément de description
ariaInvalidbooleanundefinedIndique si la valeur est invalide
ariaRequiredbooleanundefinedIndique si le champ est requis
ariaValueTextstringundefinedDescription textuelle de la valeur

Events

EventTypeDescription
@update:modelValue(value: number | [number, number]) => voidÉmis lors du changement de valeur (v-model)
@change(value: number | [number, number]) => voidÉmis lors du changement
@input(value: number | [number, number]) => voidÉmis pendant le glissement
@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

Slots

SlotDescription
beforeContenu affiché avant le slider
afterContenu affiché après le slider

Méthodes exposées

MéthodeTypeDescription
focus()() => voidDonne le focus au slider
sliderRefRef<HTMLDivElement>Référence au conteneur
thumb1RefRef<HTMLDivElement>Référence au premier thumb
thumb2RefRef<HTMLDivElement>Référence au second thumb (dual)

Détection automatique du dual-range

Le composant détecte automatiquement s'il doit fonctionner en mode dual-range en vérifiant si la valeur est un tableau :

vue
<!-- Mode simple -->
<SuSlider :value="50" />

<!-- Mode dual-range (détecté automatiquement) -->
<SuSlider :value="[20, 80]" />

Tooltips

Les tooltips affichent la valeur formatée au survol ou au focus des curseurs :

🎯 Positions disponibles

  • tooltip="none" : Pas de tooltip (défaut)
  • tooltip="top" : Tooltip au-dessus du curseur
  • tooltip="bottom" : Tooltip en dessous du curseur
vue
<!-- Tooltip en haut -->
<SuSlider tooltip="top" :value="50" />

<!-- Tooltip en bas -->
<SuSlider tooltip="bottom" :value="[20, 80]" />

<!-- Pas de tooltip, affichage statique -->
<SuSlider tooltip="none" :showValue="true" :value="50" />

Marques personnalisées

Les marques permettent d'afficher des valeurs spécifiques sur le slider :

📍 Fonctionnalités des marques

  • Positionnement automatique : Calcul de la position en pourcentage
  • Filtrage intelligent : Seules les marques dans la plage min/max sont affichées
  • Formatage : Utilise la fonction formatValue si fournie
  • Support RTL : Positionnement adapté à la direction
vue
<script setup>
import { ref } from 'vue'

const temperature = ref(22)
const formatTemp = (value) => `${value}°C`
</script>

<template>
  <SuSlider 
    :min="0"
    :max="40"
    :marks="[0, 10, 18, 24, 30, 40]"
    :formatValue="formatTemp"
    tooltip="top"
    v-model="temperature"
  />
</template>

Slots before et after

Les slots permettent d'ajouter du contenu personnalisé autour du slider :

🎨 Cas d'usage

  • Icônes : Indicateurs visuels (🔇 🔊)
  • Labels : Descriptions textuelles
  • Boutons : Actions rapides (reset, presets)
  • Informations : Contexte supplémentaire
vue
<template>
  <SuSlider 
    :min="0"
    :max="100"
    v-model="brightness"
  >
    <template #before>
      <div class="slider-controls">
        <span>🌙</span>
        <span>Sombre</span>
      </div>
    </template>
    <template #after>
      <div class="slider-controls">
        <span>Lumineux</span>
        <span>☀️</span>
      </div>
    </template>
  </SuSlider>
</template>

Support RTL

Le composant gère automatiquement les langues de droite à gauche :

🌐 Fonctionnalités RTL

  • Inversion automatique : Les pourcentages sont inversés
  • Calcul adapté : Position des curseurs ajustée
  • Marques et ticks : Positionnement correct
  • Navigation clavier : Flèches adaptées à la direction
vue
<!-- Support RTL -->
<SuSlider 
  dir="rtl"
  :min="0"
  :max="100"
  :value="70"
  tooltip="top"
/>

<!-- Auto-détection -->
<SuSlider 
  dir="auto"
  :value="50"
/>

Accessibilité

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

✅ Fonctionnalités d'accessibilité

  • Rôle ARIA : role="slider" avec aria-valuemin, aria-valuemax, aria-valuenow
  • Navigation au clavier : Support des touches fléchées, Page Up/Down, Home/End
  • Orientation ARIA : aria-orientation pour les lecteurs d'écran
  • Annonces vocales : Messages pour les lecteurs d'écran lors des changements
  • Labels associés : Chaque slider a un label correctement associé via SuFormField
  • Messages d'état : Messages avec aria-live pour les lecteurs d'écran
  • Contraste des couleurs : Ratios conformes WCAG AA (4.5:1 minimum)
  • Focus visible : Indicateurs de focus clairs et contrastés
  • Tailles minimales : Thumbs de 44px minimum pour l'accessibilité tactile
  • Mode sombre : Contraste adapté automatiquement
  • Contraste élevé : Support de prefers-contrast: high
  • Réduction d'animation : Respect de prefers-reduced-motion

🎯 Bonnes pratiques

vue
<!-- Slider avec validation et accessibilité -->
<SuFormField 
  label="Niveau de difficulté"
  :required="true"
  :state="hasError ? 'error' : 'default'"
  :message="hasError ? 'Veuillez sélectionner un niveau' : 'Choisissez votre niveau'"
>
  <SuSlider 
    :min="1"
    :max="10"
    tooltip="top"
    :showTicks="true"
    ariaLabel="Sélecteur de niveau de difficulté"
    v-model="difficulty"
  />
</SuFormField>

<!-- Dual-range avec formatage -->
<SuFormField 
  label="Fourchette de prix"
  message="Définissez votre budget"
>
  <SuSlider 
    :min="0"
    :max="5000"
    :step="50"
    :value="[500, 2000]"
    tooltip="top"
    :showLabels="true"
    :formatValue="(value) => `${value}€`"
    v-model="priceRange"
  />
</SuFormField>

<!-- Slider vertical avec graduations -->
<SuFormField 
  label="Température"
>
  <SuSlider 
    :min="-10"
    :max="40"
    :step="1"
    orientation="vertical"
    tooltip="top"
    :showTicks="true"
    :showLabels="true"
    :formatValue="(value) => `${value}°C`"
    v-model="temperature"
  />
</SuFormField>
ToucheAction
TabNaviguer vers/depuis le slider
FlèchesAjuster la valeur par pas
Page UpAugmenter de 10% de la plage
Page DownDiminuer de 10% de la plage
HomeAller à la valeur minimale
EndAller à la valeur maximale

Fonctionnalités avancées

🎯 Dual-range intelligent

En mode dual-range (valeur tableau), le composant gère automatiquement :

  • Collision des thumbs : Les valeurs min/max ne peuvent pas se croiser
  • Sélection intelligente : Clic sur la track sélectionne le thumb le plus proche
  • Navigation clavier : Chaque thumb est focusable indépendamment

💬 Tooltips interactifs

Les tooltips offrent un feedback visuel immédiat :

  • Affichage au survol : Apparition fluide au hover
  • Affichage au focus : Visible lors de la navigation clavier
  • Affichage pendant le drag : Reste visible pendant le glissement
  • Formatage personnalisé : Utilise la fonction formatValue

📊 Marques personnalisées

Les marques permettent de mettre en évidence des valeurs importantes :

  • Positionnement précis : Calcul automatique de la position
  • Labels formatés : Affichage avec la fonction formatValue
  • Filtrage automatique : Seules les marques valides sont affichées
  • Style adaptatif : S'adapte à l'orientation et à la direction

🎨 Formatage flexible

La fonction formatValue permet :

  • Unités personnalisées : €, %, °C, km, etc.
  • Formatage complexe : Étoiles, barres de progression, etc.
  • Localisation : Adaptation aux différentes langues

Exemples d'usage avancés

Filtres de recherche

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

const filters = ref({
  price: [100, 500],
  distance: 20,
  rating: 4
})

const formatPrice = (value) => `${value}€`
const formatDistance = (value) => `${value} km`
const formatRating = (value) => '★'.repeat(Math.floor(value)) + (value % 1 ? '☆' : '')
</script>

<template>
  <div class="filters">
    <h3>Filtres de recherche</h3>
    
    <SuFormField 
      label="Fourchette de prix"
      message="Définissez votre budget"
    >
      <SuSlider 
        :min="0"
        :max="1000"
        :step="10"
        tooltip="top"
        :showLabels="true"
        :marks="[0, 250, 500, 750, 1000]"
        :formatValue="formatPrice"
        v-model="filters.price"
      />
    </SuFormField>
    
    <SuFormField 
      label="Distance maximale"
      message="Rayon de recherche"
    >
      <SuSlider 
        :min="0"
        :max="50"
        :step="5"
        tooltip="bottom"
        :showTicks="true"
        :showLabels="true"
        :formatValue="formatDistance"
        v-model="filters.distance"
      />
    </SuFormField>
    
    <SuFormField 
      label="Note minimale"
      message="Note minimum souhaitée"
    >
      <SuSlider 
        :min="1"
        :max="5"
        :step="0.5"
        tooltip="top"
        :marks="[1, 2, 3, 4, 5]"
        :formatValue="formatRating"
        v-model="filters.rating"
      />
    </SuFormField>
  </div>
</template>

Publié sous licence MIT.