HextaUI

Switch

Un interrupteur on/off qu'on peut toucher, presser ou faire glisser, avec un curseur qui s'étire sous le doigt et un état d'attente facultatif pour les enregistrements.

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

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

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

À l'appui, le curseur s'étire vers l'autre côté avant de rebondir de l'autre côté, pour que vous sentiez l'appui. Vous pouvez aussi saisir le curseur et le faire glisser : au-delà du milieu il bascule, en deçà il revient.

iOS

variant="ios" utilise une piste plus haute, un curseur en capsule et du vert quand il est activé. L'appui, le glissement et l'enregistrement fonctionnent de la même façon.

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

Enregistrement

Renvoyez une promesse depuis onCheckedChange et le switch bascule aussitôt, même contrôlé. Un spinner n'apparaît dans le curseur que si l'enregistrement dépasse 400ms. En cas de rejet, le switch rebascule et tremble.

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

Marques on et off

icons ajoute une coche et un anneau à la piste, pour que l'état ne repose pas sur la couleur.

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

Tailles

sm, default et 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>
  )
}

Dans un champ

Avec Field, le label et la description sont liés au 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>
  )
}

Désactivé et en lecture seule

readOnly garde la valeur visible et focalisable mais ne la modifie pas.

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

Contrôlé

Passez checked et 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>
  )
}

De droite à gauche

Le curseur part de la droite et glisse vers la gauche, et le glissement suit.

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>
  )
}
ToucheAction
SpaceEnterActive ou désactive le switch qui a le focus.
  • Le switch a le rôle switch, nommé par son label. Entourez-le d'un <label> ou utilisez Field.
  • Pendant l'enregistrement, il est aria-busy et ignore les nouveaux appuis.
  • La zone de clic est plus grande que le switch, et plus grande encore au toucher.
  • Avec la réduction des animations, le curseur se déplace instantanément et rien ne tremble.
PropTypePar défaut
checked
boolean–
defaultChecked
booleanfalse
onCheckedChangeRenvoyez une promesse pour afficher l'état d'enregistrement. En cas de rejet, un switch non contrôlé rebascule.
(checked, details) => void | Promise–
variant
"default" | "ios""default"
size
"sm" | "default" | "lg""default"
iconsAffiche des marques on et off dans la piste.
booleanfalse
name
string–
value
string–
disabled
booleanfalse
readOnly
booleanfalse
required
booleanfalse
render
ReactElement | (props, state) => ReactElement<span>
AttributDescription
data-slot="switch"La piste, avec data-size et data-variant.
data-slot="switch-thumb"Le curseur.
data-checked / data-uncheckedIndique si le switch est activé.
data-draggingPrésent pendant que le curseur est déplacé.
data-pendingPrésent tant qu'une promesse renvoyée est en attente.
--switch-w / --switch-h / --switch-thumb / --switch-thumb-wTailles de la piste et du curseur, définies par size.

Utilisé dans les blocks

Des blocks qui s’appuient sur Switch.