HextaUI

Slider

Choisissez une valeur ou une plage en glissant, en touchant la piste ou avec les touches, avec des sauts fluides et une bulle de valeur facultative.

Volume
60
import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderDemo() {
  return (
    <Slider defaultValue={60} className="max-w-xs">
      <SliderLabel>Volume</SliderLabel>
      <SliderValue />
    </Slider>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/slider.json

Ajoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.

import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"
<Slider defaultValue={[50]} max={100} step={1} aria-label="Volume" />

<Slider defaultValue={50}>
  <SliderLabel>Volume</SliderLabel>
  <SliderValue />
</Slider>

<Slider /> trace un curseur par valeur : un nombre ou un tableau d'un élément donne un slider simple, et deux éléments une plage. Des enfants comme <SliderLabel /> et <SliderValue /> se placent sur une ligne au-dessus de la piste.

Pendant le glissement, le curseur suit exactement le pointeur. Quand la valeur saute, par un appui sur la piste, une touche ou une nouvelle valeur contrôlée, le curseur et le remplissage y glissent en 180ms au lieu de se téléporter.

Slider
├── SliderLabel
└── SliderValue

Tailles

sm, default et lg mettent à l'échelle ensemble le curseur et la piste.

import { Slider } from "@/components/ui/slider"

export function SliderSizes() {
  return (
    <div className="flex w-full max-w-xs flex-col gap-8">
      <Slider size="sm" defaultValue={25} aria-label="Small" />
      <Slider defaultValue={50} aria-label="Default" />
      <Slider size="lg" defaultValue={75} aria-label="Large" />
    </div>
  )
}

Plage

Passez deux valeurs pour une plage. Nommez chaque curseur avec getAriaLabel et gardez-les écartés avec minStepsBetweenValues. Avec draggableRange, glissez n'importe où entre les curseurs pour déplacer les deux à la fois ; un toucher à cet endroit déplace toujours le curseur le plus proche.

"use client"

import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderRange() {
  return (
    <Slider
      defaultValue={[200, 800]}
      max={1000}
      step={10}
      minStepsBetweenValues={10}
      draggableRange
      format={{ style: "currency", currency: "USD", maximumFractionDigits: 0 }}
      getAriaLabel={(index) =>
        index === 0 ? "Minimum price" : "Maximum price"
      }
      className="max-w-xs"
    >
      <SliderLabel>Price</SliderLabel>
      <SliderValue />
    </Slider>
  )
}

Bulle de valeur

showValue affiche la valeur formatée au-dessus du curseur pendant le glissement ou le focus clavier. Utilisez-le à la place d'une ligne de label, car la bulle monte dans l'espace au-dessus de la piste.

import { Slider } from "@/components/ui/slider"

export function SliderValueBubble() {
  return (
    <div className="flex w-full max-w-xs flex-col gap-10 pt-8">
      <Slider
        defaultValue={0.4}
        max={1}
        step={0.01}
        format={{ style: "percent" }}
        showValue
        aria-label="Opacity"
      />
      <Slider defaultValue={[30, 70]} showValue aria-label="Range" />
    </div>
  )
}

Pas et format

step aimante la valeur, largeStep définit le saut de Page Up et de Shift + flèche, et format formate chaque nombre que le slider affiche ou annonce.

import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderSteps() {
  return (
    <Slider
      defaultValue={1}
      min={0.5}
      max={2}
      step={0.25}
      largeStep={0.5}
      format={{ minimumFractionDigits: 2 }}
      className="max-w-xs"
    >
      <SliderLabel>Playback speed</SliderLabel>
      <SliderValue />
    </Slider>
  )
}

Contrôlé

onValueChange se déclenche à chaque mouvement et onValueCommitted une fois au relâchement, ce qui est le moment d'enregistrer. Définir la valeur depuis l'extérieur est aussi fluide.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderControlled() {
  const [value, setValue] = React.useState(40)
  const [saved, setSaved] = React.useState(40)

  return (
    <div className="flex w-full max-w-xs flex-col gap-4">
      <Slider
        value={value}
        onValueChange={setValue}
        onValueCommitted={setSaved}
      >
        <SliderLabel>Brightness</SliderLabel>
        <SliderValue />
      </Slider>
      <div className="flex items-center justify-between gap-3">
        <span className="text-sm text-muted-foreground">Saved: {saved}</span>
        <div className="flex gap-2">
          <Button variant="outline" size="sm" onClick={() => setValue(0)}>
            Off
          </Button>
          <Button variant="outline" size="sm" onClick={() => setValue(100)}>
            Max
          </Button>
        </div>
      </div>
    </div>
  )
}

Vertical

Avec orientation="vertical", le slider remplit la hauteur de son parent, et Haut augmente la valeur.

import { Slider } from "@/components/ui/slider"

const bands = [
  { label: "60 Hz", value: 70 },
  { label: "250 Hz", value: 45 },
  { label: "1 kHz", value: 55 },
  { label: "4 kHz", value: 80 },
  { label: "16 kHz", value: 35 },
]

export function SliderVertical() {
  return (
    <div className="flex h-48 gap-6">
      {bands.map((band) => (
        <div key={band.label} className="flex flex-col items-center gap-3">
          <Slider
            orientation="vertical"
            defaultValue={band.value}
            aria-label={band.label}
          />
          <span className="text-xs text-muted-foreground tabular-nums">
            {band.label}
          </span>
        </div>
      ))}
    </div>
  )
}

Avec des icônes

Placez des icônes à côté du slider dans une rangée flex. Le slider prend la largeur restante.

import { IconVolume, IconVolume3 } from "@tabler/icons-react"

import { Slider } from "@/components/ui/slider"

export function SliderIcons() {
  return (
    <div className="flex w-full max-w-xs items-center gap-3 text-muted-foreground">
      <IconVolume3 className="size-4 shrink-0" aria-hidden />
      <Slider defaultValue={50} aria-label="Volume" />
      <IconVolume className="size-4 shrink-0" aria-hidden />
    </div>
  )
}

Désactivé

Tout le slider s'atténue et ignore la souris et le clavier.

import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderDisabled() {
  return (
    <Slider defaultValue={30} disabled className="max-w-xs">
      <SliderLabel>Bass boost</SliderLabel>
      <SliderValue />
    </Slider>
  )
}

Libellés longs

Les longs labels passent à la ligne et la valeur reste à la fin.

import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderLongLabel() {
  return (
    <Slider
      defaultValue={[1200, 48000]}
      min={0}
      max={50000}
      step={100}
      format={{ style: "currency", currency: "USD", maximumFractionDigits: 0 }}
      className="max-w-xs"
    >
      <SliderLabel>
        Annual household income before taxes, including side projects
      </SliderLabel>
      <SliderValue />
    </Slider>
  )
}

De droite à gauche

Dans un parent de droite à gauche, le remplissage part de la droite et les flèches le suivent. Passez locale pour les chiffres du lecteur.

import { Slider, SliderLabel, SliderValue } from "@/components/ui/slider"

export function SliderRtl() {
  return (
    <div dir="rtl" className="flex w-full max-w-xs flex-col gap-8">
      <Slider defaultValue={65} locale="ar-EG">
        <SliderLabel>مستوى الصوت</SliderLabel>
        <SliderValue />
      </Slider>
      <Slider defaultValue={[20, 70]} locale="ar-EG" draggableRange>
        <SliderLabel>النطاق</SliderLabel>
        <SliderValue />
      </Slider>
    </div>
  )
}
ToucheAction
TabPlace le focus sur le curseur suivant.
→↑Augmente la valeur d'un pas. → la diminue en droite à gauche.
←↓Diminue la valeur d'un pas. ← l'augmente en droite à gauche.
Shift + ArrowPage UpPage DownAvance de largeStep.
HomeDéfinit le minimum, ou la valeur du curseur précédent dans une plage.
EndDéfinit le maximum, ou la valeur du curseur suivant dans une plage.
  • Chaque curseur contient un input type="range" natif : c'est donc un slider avec sa propre valeur, son min et son max.
  • <SliderLabel /> nomme chaque curseur. Sans lui, aria-label sur <Slider /> est transmis aux curseurs, pas au wrapper, de sorte que le slider n'est jamais sans nom. Dans une plage, utilisez getAriaLabel pour distinguer les curseurs.
  • <SliderValue /> et la bulle de valeur ne sont pas annoncés à chaque changement ; le curseur indique déjà sa valeur.
  • Appuyer sur un curseur n'affiche pas d'anneau de focus ; les flèches, si. Avec la réduction des animations, le curseur saute au lieu de glisser.
  • Sur écran tactile, la zone de clic passe à au moins 44px sans changer la mise en page.

Construit sur le slider de Base UI. Chaque partie accepte les props de la primitive qu'elle enveloppe.

PropTypePar défaut
valueLa valeur contrôlée. Un curseur par élément.
number | number[]–
defaultValue
number | number[]–
onValueChangeSe déclenche à chaque changement pendant le glissement.
(value, eventDetails) => void–
onValueCommittedSe déclenche une fois à la fin d'un changement.
(value, eventDetails) => void–
min
number0
max
number100
step
number1
largeStep
number10
minStepsBetweenValues
number0
size
"sm" | "default" | "lg""default"
orientation
"horizontal" | "vertical""horizontal"
draggableRangeDans une plage, glisser entre les curseurs les déplace ensemble en gardant l'écart.
booleanfalse
showValueAffiche la valeur au-dessus du curseur pendant le glissement ou le focus clavier.
booleanfalse
thumbAlignmentedge garde le curseur dans la piste à min et max.
"edge" | "center" | "edge-client-only""edge"
thumbCollisionBehavior
"push" | "swap" | "none""push"
format
Intl.NumberFormatOptions–
locale
Intl.LocalesArgument"en-US"
aria-labelNomme les curseurs.
string–
getAriaLabelNomme chaque curseur d'une plage.
(index: number) => string–
getAriaValueText
(formattedValue: string, value: number, index: number) => string–
name
string–
disabled
booleanfalse
className
string | (state) => string–
render
ReactElement | (props, state) => ReactElement<div>
AttributDescription
data-slot="slider"La racine.
data-sizesm, default ou lg.
data-jumpPrésent pendant 220ms tandis que le curseur glisse vers une nouvelle valeur.
data-range-draggingPrésent tant que toute la plage est déplacée.
data-orientationhorizontal ou vertical.
data-draggingPrésent tant qu'un pointeur est enfoncé.
data-disabledPrésent lorsque l’élément est désactivé.
data-invalidPrésent quand il est invalide dans un Field.
--slider-thumbLe diamètre du curseur, défini par size.
--slider-trackL'épaisseur de la piste, définie par size.
data-slot="slider-control"La zone cliquable autour de la piste.
data-slot="slider-track"La piste.
data-slot="slider-range"Le remplissage entre le début, ou le premier curseur, et le dernier curseur.
data-slot="slider-thumb"Chaque curseur. data-index donne sa position.
data-activeSur le curseur qui a le focus ou qui est déplacé.
data-slot="slider-thumb-value"La bulle de valeur de showValue.

Nomme les curseurs et s'étend pour remplir la ligne. Rend un <div>.

PropTypePar défaut
render
ReactElement | (props, state) => ReactElement<div>
AttributDescription
data-slot="slider-label"Le libellé.

Affiche les valeurs formatées, jointes par un tiret demi-cadratin dans une plage. Rend un <output>.

PropTypePar défaut
childrenTexte personnalisé.
(formattedValues: string[], values: number[]) => ReactNode–
render
ReactElement | (props, state) => ReactElement<output>
AttributDescription
data-slot="slider-value"La valeur.
data-orientationhorizontal ou vertical.
data-draggingPrésent tant qu'un pointeur est enfoncé.
data-disabledPrésent lorsque l’élément est désactivé.
data-invalidPrésent quand il est invalide dans un Field.

Utilisé dans les blocks

Des blocks qui s’appuient sur Slider.