HextaUI

Slider

Escolha um valor ou um intervalo arrastando, tocando na trilha ou usando as teclas, com saltos que deslizam e um balão de valor opcional.

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

Adiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.

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 /> desenha um thumb por valor, então um número ou um array de um item cria um slider simples e dois itens criam um intervalo. Filhos como <SliderLabel /> e <SliderValue /> ficam em uma linha acima da trilha.

Enquanto você arrasta, o thumb segue o ponteiro exatamente. Quando o valor salta, por um toque na trilha, uma tecla ou um novo valor controlado, o thumb e o preenchimento deslizam até lá em 180ms em vez de se teletransportar.

Slider
├── SliderLabel
└── SliderValue

Tamanhos

sm, default e lg escalam o thumb e a trilha juntos.

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>
  )
}

Intervalo

Passe dois valores para um intervalo. Dê nome a cada thumb com getAriaLabel e mantenha-os afastados com minStepsBetweenValues. Com draggableRange, arraste em qualquer ponto entre os thumbs para mover os dois de uma vez; um toque ali ainda move o thumb mais próximo.

"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>
  )
}

Balão de valor

showValue mostra o valor formatado acima do thumb enquanto é arrastado ou tem foco do teclado. Use no lugar de uma linha de rótulo, já que o balão sobe para o espaço acima da trilha.

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>
  )
}

Passos e formato

step ajusta o valor, largeStep define o salto de Page Up e Shift + seta, e format formata todo número que o slider mostra ou anuncia.

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>
  )
}

Controlado

onValueChange dispara a cada movimento e onValueCommitted uma vez ao soltar, que é o momento de salvar. Definir o valor de fora também desliza.

"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

Com orientation="vertical" o slider preenche a altura do pai, e Up aumenta o valor.

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>
  )
}

Com ícones

Coloque ícones ao lado do slider em uma linha flex. O slider ocupa a largura 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>
  )
}

Desabilitado

O slider inteiro escurece e ignora a entrada de ponteiro e de teclado.

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>
  )
}

Rótulos longos

Rótulos longos quebram linha, e o valor fica no final.

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>
  )
}

Da direita para a esquerda

Dentro de um pai da direita para a esquerda, o preenchimento começa pela direita e as setas o acompanham. Passe locale para os dígitos do leitor.

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>
  )
}
TeclaAção
TabMove o foco para o próximo thumb.
→↑Aumenta o valor em um passo. → diminui da direita para a esquerda.
←↓Diminui o valor em um passo. ← aumenta da direita para a esquerda.
Shift + ArrowPage UpPage DownMove por largeStep.
HomeDefine o mínimo, ou o valor do thumb anterior em um intervalo.
EndDefine o máximo, ou o valor do próximo thumb em um intervalo.
  • Cada thumb contém um input type="range" nativo, então é um slider com seu próprio valor, min e max.
  • <SliderLabel /> dá nome a cada thumb. Sem um, o aria-label em <Slider /> é passado aos thumbs, não ao wrapper, para o slider nunca ficar sem nome. Em um intervalo, use getAriaLabel para distinguir os thumbs.
  • <SliderValue /> e o balão de valor não são anunciados a cada mudança; o thumb já informa seu valor.
  • Pressionar um thumb não mostra anel de foco; as setas mostram. Com movimento reduzido, o thumb salta em vez de deslizar.
  • Em telas touch, a área de toque cresce para pelo menos 44px sem alterar o layout.

Construído sobre o slider do Base UI. Cada parte aceita as props da primitiva que envolve.

PropTipoPadrão
valueO valor controlado. Um thumb por item.
number | number[]–
defaultValue
number | number[]–
onValueChangeDispara a cada mudança durante o arrasto.
(value, eventDetails) => void–
onValueCommittedDispara uma vez quando uma mudança termina.
(value, eventDetails) => void–
min
number0
max
number100
step
number1
largeStep
number10
minStepsBetweenValues
number0
size
"sm" | "default" | "lg""default"
orientation
"horizontal" | "vertical""horizontal"
draggableRangeEm um intervalo, arrastar entre os thumbs os move juntos, mantendo a distância.
booleanfalse
showValueMostra o valor acima do thumb durante o arrasto ou com foco do teclado.
booleanfalse
thumbAlignmentedge mantém o thumb dentro da trilha em min e max.
"edge" | "center" | "edge-client-only""edge"
thumbCollisionBehavior
"push" | "swap" | "none""push"
format
Intl.NumberFormatOptions–
locale
Intl.LocalesArgument"en-US"
aria-labelDá nome aos thumbs.
string–
getAriaLabelDá nome a cada thumb de um intervalo.
(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>
AtributoDescrição
data-slot="slider"A raiz.
data-sizesm, default ou lg.
data-jumpPresente por 220ms enquanto o thumb desliza para um novo valor.
data-range-draggingPresente enquanto o intervalo inteiro está sendo arrastado.
data-orientationhorizontal ou vertical.
data-draggingPresente enquanto um ponteiro está pressionado.
data-disabledPresente quando desabilitado.
data-invalidPresente quando inválido dentro de um Field.
--slider-thumbO diâmetro do thumb, definido por size.
--slider-trackA espessura da trilha, definida por size.
data-slot="slider-control"A área pressionável em volta da trilha.
data-slot="slider-track"A trilha.
data-slot="slider-range"O preenchimento entre o início, ou o primeiro thumb, e o último thumb.
data-slot="slider-thumb"Cada thumb. data-index informa sua posição.
data-activeNo thumb que tem foco ou está sendo arrastado.
data-slot="slider-thumb-value"O balão de valor de showValue.

Dá nome aos thumbs e cresce para preencher a linha. Renderiza um <div>.

PropTipoPadrão
render
ReactElement | (props, state) => ReactElement<div>
AtributoDescrição
data-slot="slider-label"O rótulo.

Mostra os valores formatados, unidos por um travessão en em um intervalo. Renderiza um <output>.

PropTipoPadrão
childrenTexto personalizado.
(formattedValues: string[], values: number[]) => ReactNode–
render
ReactElement | (props, state) => ReactElement<output>
AtributoDescrição
data-slot="slider-value"O valor.
data-orientationhorizontal ou vertical.
data-draggingPresente enquanto um ponteiro está pressionado.
data-disabledPresente quando desabilitado.
data-invalidPresente quando inválido dentro de um Field.

Usado em blocos

Blocos que se baseiam em Slider.