スイッチ

スイッチは、2つの状態間で値を切り替えるための快適なインターフェースであり、ネイティブのチェックボックス要素と同じセマンティクスとキーボードナビゲーションを提供します。

開始するには、npm 経由で Headless UI をインストールします。

npm install @headlessui/react

スイッチは、`Switch` コンポーネントを使用して構築されています。コンポーネントを直接クリックするか、フォーカスされている間にスペースバーを押して、スイッチを切り替えることができます。

スイッチを切り替えると、`checked` 値の反転バージョンを使用して `onChange` 関数が呼び出されます。

import { Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <Switch
      checked={enabled}
      onChange={setEnabled}
      className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600"
    >
      <span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" />
    </Switch>
  )
}

Headless UI は、スイッチがオンかどうか、ポップオーバーが開いているか閉じているか、キーボードで現在フォーカスされているメニューのアイテムなどが、各コンポーネントに関する多くの状態を追跡します。

しかし、コンポーネントはヘッドレスであり、すぐに使える状態では完全にスタイルが適用されていないため、自分で各状態に望ましいスタイルを提供するまで、UIでこの情報を確認できません。

Headless UI コンポーネントのさまざまな状態をスタイリングする最も簡単な方法は、各コンポーネントが公開する `data-*` 属性を使用することです。

たとえば、`Switch` コンポーネントは `data-checked` 属性(スイッチが現在オンかどうかを示す)と `data-disabled` 属性(スイッチが現在無効かどうかを示す)を公開します。

<!-- Rendered `Switch` -->
<button data-checked data-disabled>
  <!-- ... -->
</button>

これらのデータ属性の存在に基づいて条件付きでスタイルを適用するには、CSS 属性セレクター を使用します。Tailwind CSS を使用している場合は、データ属性修飾子 を使用すると簡単です。

import { Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <Switch
      checked={enabled}
      onChange={setEnabled}
className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 data-[checked]:bg-blue-600 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50"
>
<span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" />
</Switch> ) }

使用可能なすべてのデータ属性のリストについては、コンポーネントAPI を参照してください。

各コンポーネントは、レンダープロップス を介して現在の状態に関する情報を公開しており、これを使用して条件付きで異なるスタイルを適用したり、異なるコンテンツをレンダリングしたりできます。

たとえば、`Switch` コンポーネントは `checked` 状態(スイッチが現在オンかどうかを示す)と `disabled` 状態(スイッチが現在無効かどうかを示す)を公開します。

import { Switch } from '@headlessui/react'
import clsx from 'clsx'
import { Fragment, useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <Switch checked={enabled} onChange={setEnabled} as={Fragment}>
{({ checked, disabled }) => (
<button className={clsx( 'group inline-flex h-6 w-11 items-center rounded-full',
checked ? 'bg-blue-600' : 'bg-gray-200',
disabled && 'cursor-not-allowed opacity-50'
)}
>
<span className="sr-only">Enable notifications</span> <span
className={clsx('size-4 rounded-full bg-white transition', checked ? 'translate-x-6' : 'translate-x-1')}
/>
</button>
)}
</Switch> ) }

使用可能なすべてのレンダープロップスのリストについては、コンポーネントAPI を参照してください。

`Label` と `Switch` を `Field` コンポーネントでラップして、生成された ID を使用して自動的に関連付けます。

import { Field, Label, Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
<Field>
<Label>Enable notifications</Label>
<Switch checked={enabled} onChange={setEnabled} className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600" > <span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch>
</Field>
) }

デフォルトでは、`Label` をクリックすると `Switch` が切り替わり、ネイティブのHTMLチェックボックスのラベルと同じように動作します。`Label` をクリック不可にする場合は、`Label` コンポーネントに `passive` プロップを追加できます。

<Label passive>Enable beta features</Label>

`aria-describedby` 属性を使用して `Switch` と自動的に関連付けるには、`Field` 内に `Description` コンポーネントを使用します。

import { Description, Field, Label, Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
<Field>
<Label>Enable notifications</Label>
<Description>Get notified about important changes in your projects.</Description>
<Switch checked={enabled} onChange={setEnabled} className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600" > <span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch>
</Field>
) }

`Switch` と関連付けられた `Label` と `Description` を無効にするには、`Field` コンポーネントに `disabled` プロップを追加します。

import { Description, Field, Label, Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
<Field disabled>
<Label className="data-[disabled]:opacity-50">Enable notifications</Label> <Description className="data-[disabled]:opacity-50"> Get notified about important changes in your projects. </Description> <Switch checked={enabled} onChange={setEnabled} className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50" > <span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch> </Field> ) }

`Switch` 自体に `disabled` プロップを追加することで、`Field` の外でもスイッチを無効化できます。

`Switch` に `name` プロップを追加すると、非表示の `input` 要素がレンダリングされ、スイッチの状態と同期されます。

import { Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <form action="/accounts" method="post">
      <Switch
        checked={enabled}
        onChange={setEnabled}
name="terms-of-service"
className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600" >
<span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch> <button>Submit</button> </form> ) }

これにより、ネイティブのHTML `

` 内でスイッチを使用し、スイッチがネイティブのHTMLフォームコントロールであるかのように、従来のフォーム送信を行うことができます。

デフォルトでは、スイッチがオンの場合の値は `on` であり、スイッチがオフの場合は存在しません。

<!-- Rendered hidden input -->
<input type="hidden" name="terms-of-service" value="on" />

`value` プロップを使用して、必要に応じて値をカスタマイズできます。

import { Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <form action="/accounts" method="post">
      <Switch
        checked={enabled}
        onChange={setEnabled}
        name="terms-of-service"
value="accept"
className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600" >
<span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch> <button>Submit</button> </form> ) }

スイッチがオンの場合、非表示の入力はカスタム値を使用します。

<!-- Rendered hidden input -->
<input type="hidden" name="terms-of-service" value="accept" />

文字列などの基本的な値は、その値を含む単一の非表示入力としてレンダリングされますが、オブジェクトなどの複雑な値は、名前の角括弧表記を使用して複数の入力にエンコードされます。

`checked` プロップを省略すると、Headless UI は内部的にその状態を追跡するため、非制御コンポーネント として使用できます。

非制御の場合、`defaultChecked` プロップを使用して、デフォルトで `Switch` をオンにすることができます。

import { Switch } from '@headlessui/react'

function Example() {
  return (
    <form action="/accounts" method="post">
      <Switch
defaultChecked={true}
name="terms-of-service" className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600" >
<span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch> <button>Submit</button> </form> ) }

これは、HTMLフォーム と一緒にスイッチを使用する場合、またはReactの状態を使用して追跡するのではなく、FormData を使用して状態を収集するフォームAPIと 함께 使用する場合に、コードを簡素化できます。

コンポーネントの値が変更された場合、提供した `onChange` プロップは引き続き呼び出されます(副作用を実行する必要がある場合)。ただし、コンポーネントの状態を自分で追跡する必要はありません。

スイッチは通常、DOM に常にレンダリングされるため(他のコンポーネントのようにマウント/アンマウントされるわけではありません)、単純なCSSトランジションでスイッチをアニメーション化することがよくあります。

import { Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <Switch
      checked={enabled}
      onChange={setEnabled}
className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600"
>
<span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" />
</Switch> ) }

レンダリングレスであるため、Headless UI コンポーネントは、Framer MotionReact Spring などのReactエコシステムの他のアニメーションライブラリと組み合わせることができます。

`Switch` コンポーネントはデフォルトで `button` をレンダリングします。

`as` プロップを使用して、コンポーネントを異なる要素または独自の カスタムコンポーネントとしてレンダリングします。カスタムコンポーネントが forward refs を使用していることを確認して、Headless UI が正しく接続できるようにします。

import { Switch } from '@headlessui/react'
import { useState } from 'react'

function Example() {
  const [enabled, setEnabled] = useState(false)

  return (
    <Switch
as="div"
checked={enabled} onChange={setEnabled} className="group inline-flex h-6 w-11 items-center rounded-full bg-gray-200 transition data-[checked]:bg-blue-600" >
<span className="size-4 translate-x-1 rounded-full bg-white transition group-data-[checked]:translate-x-6" /> </Switch> ) }

コマンド説明

スペース`Switch` がフォーカスされているとき

スイッチを切り替えます。

Enterフォーム内にあるとき

フォームを送信します。

メインのスイッチコンポーネントです。

プロップデフォルト説明
asbutton
文字列 | コンポーネント

スイッチがレンダリングされる要素またはコンポーネント。スイッチとしてレンダリングする必要があります。

checked
ブール値

スイッチがオンかどうか。

defaultChecked
T

非制御コンポーネントとして使用する場合のデフォルトのオン値。

onChange
(value: Boolean) => void

スイッチが切り替えられたときに呼び出す関数。

name
文字列

フォーム内で使用する場合の名前。スイッチフォーム内

form
文字列

所属するフォームのID。スイッチに属します。

`name` が指定されているが `form` が指定されていない場合、スイッチ自身の状態を最も近い祖先であるform要素に追加します。

文字列

このコンポーネントをフォーム内で使用する場合、チェックされているときの値。

データ属性レンダープロップ説明
data-checkedchecked

ブール値

〜かどうかスイッチチェックされています。

data-無効化無効化

ブール値

〜かどうかスイッチ無効化されています。

data-フォーカスフォーカス

ブール値

〜かどうかスイッチフォーカスされています。

data-ホバーホバー

ブール値

〜かどうかスイッチホバーされています。

data-アクティブアクティブ

ブール値

〜かどうかスイッチアクティブまたは押された状態です。

data-自動フォーカス自動フォーカス

ブール値

autoFocusプロップがtrueに設定されているかどうか。

data-変更中変更中

ブール値

チェック状態が現在変更中かどうか。

checked状態が変更されると、トランジションを微調整できるように、changingは2つのアニメーションフレームの間trueになります。

LabelDescription、およびフォームコントロールをグループ化します。

プロップデフォルト説明
asdiv
文字列 | コンポーネント

スイッチがレンダリングされる要素またはコンポーネント。フィールドとしてレンダリングする必要があります。

無効化false
ブール値

フィールドが無効化されているかどうか。

データ属性レンダープロップ説明
data-無効化無効化

ブール値

フィールドが無効化されているかどうか。

Labelコンポーネントはフォームコントロールにラベルを付けます。

プロップデフォルト説明
aslabel
文字列 | コンポーネント

スイッチがレンダリングされる要素またはコンポーネント。labelとしてレンダリングする必要があります。

パッシブfalse
ブール値

trueの場合、ラベルをクリックしても関連付けられたフォームコントロールにフォーカスされません。

データ属性レンダープロップ説明
data-無効化無効化

ブール値

Fieldが無効化されているかどうか。

Descriptionコンポーネントはフォームコントロールを説明します。

プロップデフォルト説明
asp
文字列 | コンポーネント

スイッチがレンダリングされる要素またはコンポーネント。説明としてレンダリングする必要があります。

データ属性レンダープロップ説明
data-無効化無効化

ブール値

Fieldが無効化されているかどうか。

事前にデザインされたTailwind CSS トグルとスイッチの例(Headless UI を使用)に興味がある場合Tailwind UIをご覧ください。これは、私たちが作成した美しくデザインされ、専門的に作られたコンポーネントのコレクションです。

これは、このようなオープンソースプロジェクトへの私たちの取り組みを支援する素晴らしい方法であり、それらを改善し、適切に維持することを可能にします。