スイッチ (トグル)
スイッチは、値を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> <spanclass="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
コンポーネントを使用できます。
この例では、SwitchGroup
、Switch
、およびSwitchLabel
コンポーネントを使用して、ボタンの兄弟としてラベルをレンダリングする方法を示します。SwitchLabel
はSwitch
コンポーネントとともに動作し、両方とも親の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 | スイッチを切り替えます |
Enter フォーム内にある場合 | フォームを送信します |
プロパティ | デフォルト | 説明 |
as | button | 文字列 | コンポーネント
|
v-model | — | ブール値 スイッチがオンになっているかどうか。 |
defaultChecked | — | T 非制御コンポーネントとして使用する場合のデフォルトのチェック済み値。 |
name | — | 文字列 このコンポーネントをフォーム内で使用する場合に使用する名前。 |
value | — | 文字列 チェックされている場合、このコンポーネントをフォーム内で使用する場合に使用する値。 |
スロットプロパティ | 説明 |
checked |
スイッチがオンになっているかどうか。 |
プロパティ | デフォルト | 説明 |
as | label | 文字列 | コンポーネント
|
passive | false | ブール値 trueの場合、ラベルをクリックしても |
プロパティ | デフォルト | 説明 |
as | p | 文字列 | コンポーネント
|
プロパティ | デフォルト | 説明 |
as | template | 文字列 | コンポーネント
|