HextaUI

Toggle

オンとオフを保持するボタンです。押すと塗りが定着し、ホバーからオンへの変化が明確で、アイコンを状態に合わせて塗りつぶせます。

import { IconBold, IconItalic, IconUnderline } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleDemo() {
  return (
    <div className="flex items-center gap-1">
      <Toggle aria-label="Bold" defaultPressed>
        <IconBold />
      </Toggle>
      <Toggle aria-label="Italic">
        <IconItalic />
      </Toggle>
      <Toggle aria-label="Underline">
        <IconUnderline />
      </Toggle>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/toggle.json

コンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。

import { Toggle } from "@/components/ui/toggle"
<Toggle aria-label="Bold">
  <IconBold />
</Toggle>

オフの toggle にホバーすると淡い色味が表示され、オンにすると濃い塗りが定着してラベルが最大のコントラストになるため、オンがホバーに見えることはありません。

アウトライン

variant="outline" は境界線と面を追加します。単独で置く toggle 向けです。

import { IconBookmark } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleOutline() {
  return (
    <div className="flex items-center gap-2">
      <Toggle variant="outline" aria-label="Bookmark">
        <IconBookmark />
      </Toggle>
      <Toggle variant="outline">
        <IconBookmark />
        Bookmark
      </Toggle>
    </div>
  )
}

テキスト付き

アイコンとラベルが並びます。表示されるテキストを持つ toggle には aria-label は不要です。

import { IconItalic, IconTextWrap } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleText() {
  return (
    <div className="flex flex-wrap items-center gap-2">
      <Toggle>
        <IconItalic />
        Italic
      </Toggle>
      <Toggle variant="outline" defaultPressed>
        <IconTextWrap />
        Wrap lines
      </Toggle>
      <Toggle variant="outline">Show hidden files</Toggle>
    </div>
  )
}

オン時は塗りつぶし

outline のアイコンに group-data-pressed/toggle:fill-current を追加すると、toggle がオンになるとき塗りつぶされます。

import { IconBookmark, IconHeart, IconStar } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleFilledIcon() {
  return (
    <div className="flex items-center gap-1">
      <Toggle aria-label="Like" defaultPressed>
        <IconHeart className="group-data-pressed/toggle:fill-current" />
      </Toggle>
      <Toggle aria-label="Star">
        <IconStar className="group-data-pressed/toggle:fill-current" />
      </Toggle>
      <Toggle aria-label="Save">
        <IconBookmark className="group-data-pressed/toggle:fill-current" />
      </Toggle>
    </div>
  )
}

サイズ

sm、default、lg。アイコンのみの toggle は正方形のままです。

import { IconBold } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleSizes() {
  return (
    <div className="flex flex-col gap-4">
      <div className="flex items-center gap-2">
        <Toggle size="sm" aria-label="Bold, small">
          <IconBold />
        </Toggle>
        <Toggle aria-label="Bold">
          <IconBold />
        </Toggle>
        <Toggle size="lg" aria-label="Bold, large">
          <IconBold />
        </Toggle>
      </div>
      <div className="flex items-center gap-2">
        <Toggle size="sm" variant="outline">
          Small
        </Toggle>
        <Toggle variant="outline">Default</Toggle>
        <Toggle size="lg" variant="outline">
          Large
        </Toggle>
      </div>
    </div>
  )
}

Pill

shape="pill" は両端を完全に丸めます。チャットのコンポーザーのような、角丸の面の内側にある toggle 向けです。

import { IconSparkles, IconWorld } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function TogglePill() {
  return (
    <div className="flex flex-wrap items-center gap-2">
      <Toggle shape="pill" defaultPressed>
        <IconSparkles />
        Think
      </Toggle>
      <Toggle shape="pill" variant="outline">
        <IconWorld />
        Search
      </Toggle>
    </div>
  )
}

無効

無効な toggle はオンかどうかを表示し続けますが、押すこともフォーカスすることもできません。

import { IconBold, IconUnderline } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleDisabled() {
  return (
    <div className="flex items-center gap-2">
      <Toggle disabled aria-label="Bold">
        <IconBold />
      </Toggle>
      <Toggle disabled defaultPressed aria-label="Underline">
        <IconUnderline />
      </Toggle>
      <Toggle disabled variant="outline">
        Read-only mode
      </Toggle>
    </div>
  )
}

制御

pressed と onPressedChange を渡します。ラベルは変わらず、アイコンが状態に従います。

"use client"

import * as React from "react"
import { IconMicrophone, IconMicrophoneOff } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleControlled() {
  const [muted, setMuted] = React.useState(false)

  return (
    <div className="flex items-center gap-3 text-sm">
      <Toggle
        variant="outline"
        aria-label="Mute microphone"
        pressed={muted}
        onPressedChange={setMuted}
      >
        {muted ? <IconMicrophoneOff /> : <IconMicrophone />}
      </Toggle>
      <span className="text-muted-foreground">
        Microphone is {muted ? "muted" : "on"}
      </span>
    </div>
  )
}

右から左

アイコンがラベルの右側で先行します。

import { IconAlignRight, IconBold, IconItalic } from "@tabler/icons-react"

import { Toggle } from "@/components/ui/toggle"

export function ToggleRtl() {
  return (
    <div dir="rtl" className="flex items-center gap-2">
      <Toggle variant="outline" defaultPressed>
        <IconBold />
        عريض
      </Toggle>
      <Toggle variant="outline">
        <IconItalic />
        مائل
      </Toggle>
      <Toggle variant="outline" aria-label="محاذاة لليمين">
        <IconAlignRight />
      </Toggle>
    </div>
  )
}
キーアクション
SpaceEnterフォーカスされている toggle をオンまたはオフにします。
Tab次の toggle にフォーカスを移します。
  • toggle は aria-pressed を持つ button なので、スクリーンリーダーがオンかどうかを読み上げます。
  • アイコンのみの toggle には、操作を表す aria-label(「Mute microphone」など)を付け、両方の状態で同じに保ってください。押下状態に加えてこれも変えると、二重否定のように読み上げられます。
  • タッチスクリーンではヒット領域が最低44pxまで広がります。ただし、隣が重なってしまう toggle group の内側は除きます。
  • 視差効果の軽減が有効な場合、拡大縮小は行われず、塗りがフェードするだけです。
プロパティ型デフォルト
variant
"default" | "outline""default"
size
"default" | "sm" | "lg""default"
shape
"default" | "pill""default"
pressed
boolean–
defaultPressed
booleanfalse
onPressedChange
(pressed, details) => void–
disabled
booleanfalse
valuetoggle group の中でその toggle を識別します。
string–
className
string | (state) => string–
nativeButton
booleantrue
render
ReactElement | (props, state) => ReactElement<button>
属性説明
data-slot="toggle"ボタン。data-variant と data-size を持ちます。
data-pressedtoggle がオンのときに付きます。
data-disabledtoggle が無効なときに付きます。

使用しているブロック

Toggle の上に構築されるブロック。