HextaUI

Switch

Um toggle de ligar/desligar que você pode tocar, pressionar ou arrastar, com um thumb que se estica sob o dedo e um estado pendente opcional para salvamentos.

import { Switch } from "@/components/ui/switch"

const settings = [
  {
    id: "wifi",
    title: "Wi-Fi",
    description: "Join known networks automatically.",
    on: true,
  },
  {
    id: "bluetooth",
    title: "Bluetooth",
    description: "Connect to headphones and keyboards.",
    on: false,
  },
  {
    id: "airdrop",
    title: "Nearby sharing",
    description: "Let people around you send files.",
    on: true,
  },
]

export function SwitchDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col divide-y rounded-xl border">
      {settings.map((setting) => (
        <label
          key={setting.id}
          className="flex items-center justify-between gap-4 p-4 text-sm"
        >
          <span className="flex flex-col gap-0.5">
            <span className="font-medium">{setting.title}</span>
            <span className="text-muted-foreground">{setting.description}</span>
          </span>
          <Switch defaultChecked={setting.on} />
        </label>
      ))}
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/switch.json

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

import { Switch } from "@/components/ui/switch"
<label className="flex items-center gap-3">
  <Switch defaultChecked />
  Wi-Fi
</label>

Ao pressionar, o thumb se estica em direção ao outro lado antes de atravessar com efeito de mola, para você sentir o toque. Você também pode agarrar o thumb e arrastá-lo: passando do meio ele vira, antes disso ele volta.

iOS

variant="ios" usa uma trilha mais alta, um thumb em cápsula e verde quando ligado. Pressionar, arrastar e salvar funcionam do mesmo jeito.

import { Switch } from "@/components/ui/switch"

export function SwitchIos() {
  return (
    <div className="flex flex-col gap-4 text-sm">
      <label className="flex items-center gap-3">
        <Switch variant="ios" />
        Airplane mode
      </label>
      <label className="flex items-center gap-3">
        <Switch variant="ios" defaultChecked />
        Wi-Fi
      </label>
      <div className="flex items-center gap-4">
        <Switch variant="ios" size="sm" aria-label="Small" defaultChecked />
        <Switch variant="ios" size="lg" aria-label="Large" defaultChecked />
      </div>
    </div>
  )
}

Salvando

Retorne uma promise de onCheckedChange e o switch vira na hora, mesmo controlado. Um spinner aparece no thumb só se o salvamento levar mais de 400ms. Se for rejeitada, o switch volta e treme.

"use client"

import { Switch } from "@/components/ui/switch"

function save(succeed: boolean) {
  return new Promise<void>((resolve, reject) =>
    setTimeout(() => (succeed ? resolve() : reject(new Error("Offline"))), 1200)
  )
}

export function SwitchAsync() {
  return (
    <div className="flex flex-col gap-4 text-sm">
      <label className="flex items-center gap-3">
        <Switch onCheckedChange={() => save(true)} />
        Sync to cloud (saves)
      </label>
      <label className="flex items-center gap-3">
        <Switch defaultChecked onCheckedChange={() => save(false)} />
        Public profile (fails and flips back)
      </label>
    </div>
  )
}

Marcas de ligado e desligado

icons adiciona um check e um anel à trilha, para o estado não depender da cor.

import { Switch } from "@/components/ui/switch"

export function SwitchIcons() {
  return (
    <div className="flex flex-col gap-4 text-sm">
      <label className="flex items-center gap-3">
        <Switch icons defaultChecked />
        Captions
      </label>
      <label className="flex items-center gap-3">
        <Switch icons size="lg" />
        Reduce transparency
      </label>
    </div>
  )
}

Tamanhos

sm, default e lg.

import { Switch } from "@/components/ui/switch"

export function SwitchSizes() {
  return (
    <div className="flex items-center gap-6">
      <Switch size="sm" aria-label="Small" defaultChecked />
      <Switch aria-label="Default" defaultChecked />
      <Switch size="lg" aria-label="Large" defaultChecked />
    </div>
  )
}

Em um field

Com Field, o rótulo e a descrição ficam vinculados ao switch.

import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
} from "@/components/ui/field"
import { Switch } from "@/components/ui/switch"

export function SwitchField() {
  return (
    <Field orientation="horizontal" className="w-full max-w-sm">
      <FieldContent>
        <FieldLabel>Marketing emails</FieldLabel>
        <FieldDescription>
          Product news and offers, about once a month.
        </FieldDescription>
      </FieldContent>
      <Switch name="marketing" />
    </Field>
  )
}

Desabilitado e somente leitura

readOnly mantém o valor visível e focável, mas não o altera.

import { Switch } from "@/components/ui/switch"

export function SwitchStates() {
  return (
    <div className="flex flex-col gap-4 text-sm">
      <label className="flex items-center gap-3">
        <Switch disabled />
        Disabled
      </label>
      <label className="flex items-center gap-3">
        <Switch disabled defaultChecked />
        Disabled and on
      </label>
      <label className="flex items-center gap-3">
        <Switch readOnly defaultChecked />
        Read-only (managed by your admin)
      </label>
    </div>
  )
}

Controlado

Passe checked e onCheckedChange.

"use client"

import * as React from "react"

import { Switch } from "@/components/ui/switch"

export function SwitchControlled() {
  const [dark, setDark] = React.useState(false)

  return (
    <label className="flex items-center gap-3 text-sm">
      <Switch checked={dark} onCheckedChange={setDark} />
      Dark mode is {dark ? "on" : "off"}
    </label>
  )
}

Da direita para a esquerda

O thumb começa à direita e desliza para a esquerda, e o arrasto acompanha.

import { Switch } from "@/components/ui/switch"

export function SwitchRtl() {
  return (
    <div dir="rtl" className="flex flex-col gap-4 text-sm">
      <label className="flex items-center gap-3">
        <Switch defaultChecked icons />
        الإشعارات
      </label>
      <label className="flex items-center gap-3">
        <Switch />
        الوضع الداكن
      </label>
    </div>
  )
}
TeclaAção
SpaceEnterLiga ou desliga o switch com foco.
  • O switch tem o role switch nomeado por seu rótulo. Envolva-o em um <label> ou use Field.
  • Ao salvar, fica aria-busy e ignora novos toques.
  • A área de toque é maior que o switch, e maior ainda em touch.
  • Com movimento reduzido, o thumb se move instantaneamente e nada treme.
PropTipoPadrão
checked
boolean–
defaultChecked
booleanfalse
onCheckedChangeRetorne uma promise para mostrar o estado de salvamento. Em caso de rejeição, um switch não controlado volta.
(checked, details) => void | Promise–
variant
"default" | "ios""default"
size
"sm" | "default" | "lg""default"
iconsMostra marcas de ligado e desligado na trilha.
booleanfalse
name
string–
value
string–
disabled
booleanfalse
readOnly
booleanfalse
required
booleanfalse
render
ReactElement | (props, state) => ReactElement<span>
AtributoDescrição
data-slot="switch"A trilha, com data-size e data-variant.
data-slot="switch-thumb"O thumb.
data-checked / data-uncheckedSe o switch está ligado.
data-draggingPresente enquanto o thumb está sendo arrastado.
data-pendingPresente enquanto uma promise retornada está pendente.
--switch-w / --switch-h / --switch-thumb / --switch-thumb-wTamanhos da trilha e do thumb, definidos por size.

Usado em blocos

Blocos que se baseiam em Switch.