スイッチ (トグル)

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

まず、npm経由でHeadless UIをインストールしてください。

このライブラリはVue 3のみをサポートしていることに注意してください。

npm install @headlessui/vue

スイッチはSwitchコンポーネントを使用して構築され、v-modelプロパティを介してrefを受け取ります。コンポーネントを直接クリックするか、フォーカスがある状態でスペースバーを押すことで、スイッチを切り替えることができます。

スイッチを切り替えると、refが否定された値に更新されます。

<template> <Switch v-model="enabled" :class="enabled ? 'bg-blue-600' : 'bg-gray-200'" class="relative inline-flex h-6 w-11 items-center rounded-full" > <span class="sr-only">Enable notifications</span> <span :class="enabled ? 'translate-x-6' : 'translate-x-1'" class="inline-block h-4 w-4 transform rounded-full bg-white transition" /> </Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

Headless UIは、どのスイッチオプションが現在選択されているか、ポップオーバーが開いているか閉じているか、またはキーボードを介してメニューのどの項目が現在アクティブであるかなど、各コンポーネントに関する多くの状態を追跡します。

ただし、コンポーネントはヘッドレスで、初期状態では完全にスタイルが設定されていないため、各状態に必要なスタイルを自分で提供するまで、UIでこの情報を表示することはできません。

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

たとえば、Switchコンポーネントはchecked状態を公開します。これは、スイッチが現在オンになっているかどうかを示します。

<template>
<!-- Use the `checked` state to conditionally style the button. -->
<Switch v-model="enabled" as="template" v-slot="{ checked }"> <button class="relative inline-flex h-6 w-11 items-center rounded-full"
:class="checked ? 'bg-blue-600' : 'bg-gray-200'"
>
<span class="sr-only">Enable notifications</span> <span
:class="checked ? 'translate-x-6' : 'translate-x-1'"
class="inline-block h-4 w-4 transform rounded-full bg-white transition" />
</button> </Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

利用可能なすべてのスロットプロパティの完全なリストについては、コンポーネントAPIドキュメントを参照してください。

各コンポーネントは、data-headlessui-state属性を介して現在の状態に関する情報も公開します。これを使用して、条件付きで異なるスタイルを適用できます。

スロットプロパティAPIの状態のいずれかがtrueの場合、それらはスペースで区切られた文字列としてこの属性にリストされるため、[attr~=value]の形式でCSS属性セレクターを使用してそれらをターゲットにすることができます。

たとえば、スイッチがオンになっているときのSwitchコンポーネントのレンダリング結果は次のようになります。

<!-- Rendered `Switch` --> <button data-headlessui-state="checked"></button>

Tailwind CSSを使用している場合は、@headlessui/tailwindcssプラグインを使用して、ui-checked:*のような修飾子でこの属性をターゲットにできます。

<template> <Switch v-model="enabled"
class="relative inline-flex h-6 w-11 items-center rounded-full ui-checked:bg-blue-600 ui-not-checked:bg-gray-200"
>
<span class="sr-only">Enable notifications</span> <span
class="inline-block h-4 w-4 transform rounded-full bg-white transition ui-checked:translate-x-6 ui-not-checked:translate-x-1"
/>
</Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

デフォルトでは、Switchはbuttonと、それに渡されるすべての子をレンダリングします。これにより、子要素がボタン内にネストされるため、特定のUIの実装が難しくなる可能性があります。

このような状況では、柔軟性を高めるためにSwitchLabelコンポーネントを使用できます。

この例では、SwitchGroupSwitch、およびSwitchLabelコンポーネントを使用して、ボタンの兄弟としてラベルをレンダリングする方法を示します。SwitchLabelSwitchコンポーネントとともに動作し、両方とも親のSwitchGroupコンポーネント内でレンダリングする必要があることに注意してください。

<template>
<SwitchGroup>
<div class="flex items-center">
<SwitchLabel class="mr-4">Enable notifications</SwitchLabel>
<Switch v-model="enabled" :class='enabled ? "bg-blue-600" : "bg-gray-200"' class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" > <span :class='enabled ? "translate-x-6" : "translate-x-1"' class="inline-block h-4 w-4 transform rounded-full bg-white transition-transform" /> </Switch> </div>
</SwitchGroup>
</template> <script setup> import { ref } from 'vue' import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue' const enabled = ref(false) </script>

デフォルトでは、ネイティブHTMLチェックボックスのラベルと同様に、SwitchLabelをクリックするとスイッチが切り替わります。ラベルをクリック不可にする場合(デザイン上意味がない場合など)は、SwitchLabelコンポーネントにpassiveプロパティを追加できます。

<template> <SwitchGroup>
<SwitchLabel passive>Enable notifications</SwitchLabel>
<Switch v-model="enabled"> <!-- ... --> </Switch> </SwitchGroup> </template> <script setup> import { ref } from 'vue' import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue' const enabled = ref(false) </script>

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

<template> <form action="/notification-settings" method="post">
<Switch v-model="enabled" name="notifications">
<!-- ... --> </Switch> </form> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(true) </script>

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

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

<input type="hidden" name="notifications" value="on" />

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

<template> <form action="/accounts" method="post">
<Switch v-model="enabled" name="terms" value="accept">
<!-- ... --> </Switch> </form> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(true) </script>

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

<input type="hidden" name="terms" value="accept" />

checkedプロパティの代わりにdefaultCheckedプロパティをSwitchに提供すると、Headless UIは内部でその状態を追跡し、非制御コンポーネントとして使用できるようになります。

Switchコンポーネントのcheckedスロットプロパティを介して現在の状態にアクセスできます。

<template> <form action="/accounts" method="post"> <Switch name="terms-of-service"
:defaultChecked="true"
as="template" v-slot="{ checked }" >
<button :class="checked ? 'bg-blue-600' : 'bg-gray-200'" class="relative inline-flex h-6 w-11 items-center rounded-full" > <span class="sr-only">Enable notifications</span> <span :class="checked ? 'translate-x-6' : 'translate-x-1'" class="inline-block h-4 w-4 transform rounded-full bg-white transition" /> </button> </Switch> <button>Submit</button> </form> </template> <script setup> import { Switch } from '@headlessui/vue' </script>

これにより、リストボックスをHTMLフォームで使用する場合や、Reactの状態を使用して状態を追跡する代わりに、FormDataを使用して状態を収集するフォームAPIを使用する場合に、コードを簡略化できます。

コンポーネントの値が変更されたときに副作用を実行する必要がある場合に備えて、提供した@update:modelValueプロパティは引き続き呼び出されますが、コンポーネントの状態を自分で追跡するために使用する必要はありません。

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

<template> <Switch v-model="enabled"> <!-- Transition the switch's knob on state change --> <span
:class="enabled ? 'translate-x-9' : 'translate-x-0'"
class="transform transition duration-200 ease-in-out" />
<!-- ... --> </Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

デフォルトでは、Switchの子はスクリーンリーダーのラベルとして使用されます。SwitchLabelを使用している場合、Switchコンポーネントのコンテンツは支援技術によって無視されます。

SwitchまたはSwitchLabelをクリックすると、スイッチがオン/オフに切り替わります。

コマンド説明

Space Switchにフォーカスがある場合

スイッチを切り替えます

Enter フォーム内にある場合

フォームを送信します

関連するすべてのARIA属性は自動的に管理されます。

メインのSwitchコンポーネント。

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

Switchをレンダリングする要素またはコンポーネント。

v-model
ブール値

スイッチがオンになっているかどうか。

defaultChecked
T

非制御コンポーネントとして使用する場合のデフォルトのチェック済み値。

name
文字列

このコンポーネントをフォーム内で使用する場合に使用する名前。

value
文字列

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

スロットプロパティ説明
checked

ブール値

スイッチがオンになっているかどうか。

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

SwitchLabelをレンダリングする要素またはコンポーネント。

passivefalse
ブール値

trueの場合、ラベルをクリックしてもSwitchは切り替わりません。

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

Switch.Descriptionをレンダリングする要素またはコンポーネント。

プロパティデフォルト説明
astemplate
文字列 | コンポーネント

SwitchGroupをレンダリングする要素またはコンポーネント。

もしHeadless UIとTailwind CSSを使ったデザイン済みのコンポーネント例に興味がある場合は、当社が作成した美しくデザインされ、専門的に作られたコンポーネント集であるTailwind UIをご覧ください。

これは、このようなオープンソースプロジェクトにおける私たちの活動を支援する素晴らしい方法であり、それらを改善し、適切にメンテナンスし続けることを可能にします。