切換開關
切換開關提供一個愉悅的介面讓您在兩個狀態間切換一個值,而且提供了與原生核取方塊元素一樣的語意和鍵盤導覽。
要開始使用,請透過 npm 安裝 Headless UI
npm install @headlessui/react
切換器是以 Switch
元件建構的。您可以直接點選元件,或是在元件取得焦點時按空白鍵來切換。
切換切換器會呼叫 onChange
函式,並提供 checked
值的否定版本。
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 會追蹤每個元件的大量狀態,例如切換器是否已選取、快顯視窗是否已開啟或關閉,或選單中哪個項目目前已使用鍵盤取得焦點。
但由於元件是 headless,而且預設完全沒有樣式,因此除非您自行提供每個狀態需要的樣式,否則無法在使用者介面中看到這些資訊。
要為 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,以取得所有可用渲染屬性的清單。
使用 Field
元件包裝 Label
和 Switch
,以使用已產生的 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
做為不可按鈕,可以將 passive
道具加入 Label
元件中
<Label passive>Enable beta features</Label>
在 Field
內使用 Description
元件,並使用 aria-describedby
屬性自動關聯它與 Switch
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> )
}
將 disabled
道具加入 Field
元件以停用 Switch
及其相關聯的 Label
和 Description
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>
)
}
你也可以在 Field
外部停用開關,將 disabled 道具直接加入 Switch
本身即可。
如果你將 name
道具加入 Switch
,系統會產生一個隱藏的 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 <form>
中使用開關,並像你的開關為原生 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 表單的 切換,或搭配利用 FormData 收集狀態的表單 API,而不是使用 React 狀態追蹤時,這可以簡化您的程式碼。
您提供的任何 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 元件也能與 React 生態系統中的其他動畫函式庫相容,例如 Framer Motion 和 React Spring。
預設情況下,Switch
元件會呈現為一個 button
。
使用 as
屬性來將元件呈現為不同的元素或您自己的自訂元件,並確保您的自訂元件 傳遞轉發參照,以便 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>
)
}
指令 | 說明 |
空白鍵當 | 切換開關 |
Enter在表單中時 | 提交表單 |
屬性 | 預設值 | 說明 |
as | 按鈕 | 字串 | 元件 切換應該呈現為何種元件。 |
checked | - | 布林值 切換是否被勾選。 |
defaultChecked | - | T 用作非受控元件時的預設勾選值。 |
onChange | - | (value: Boolean) => void 切換被切換時呼叫的函式。 |
name | - | 字串 在表單中使用應該呈現為時使用的名稱。 |
表單 | - | 字串 所屬應該呈現為的表單 ID。 如果提供了 |
value | - | 字串 如果切換此元件,則會在表單內使用此值。 |
資料屬性 | 顯示 Prop | 說明 |
data-checked | checked |
是否應該呈現為處於已選取狀態。 |
data-disabled | disabled |
是否應該呈現為處於已停用狀態。 |
data-focus | focus |
是否應該呈現為處於焦點狀態。 |
data-hover | hover |
是否應該呈現為處於滑鼠懸停狀態。 |
data-active | active |
是否應該呈現為處於「按鈕被按下」的活躍狀態。 |
data-autofocus | autofocus |
是否已將 |
data-changing | changing |
是否正在切換已選取狀態。 當 |
將 標籤
、說明
與表單控制項分組在一起。
屬性 | 預設值 | 說明 |
as | div | 字串 | 元件 切換field何種元件。 |
disabled | false | 布林值 欄位是否已停用。 |
資料屬性 | 顯示 Prop | 說明 |
data-disabled | disabled |
欄位是否已停用。 |
標籤
元件會標記表單控制項。
屬性 | 預設值 | 說明 |
as | label | 字串 | 元件 切換label何種元件。 |
passive | false | 布林值 如果為 true,則點選標籤時不會讓表單控制項獲得焦點。 |
資料屬性 | 顯示 Prop | 說明 |
data-disabled | disabled |
父層 |
說明
元件會說明表單控制項。
屬性 | 預設值 | 說明 |
as | p | 字串 | 元件 切換description何種元件。 |
資料屬性 | 顯示 Prop | 說明 |
data-disabled | disabled |
父層 |
如果你有興趣瞭解使用 Headless UI 來建立預先設計的 Tailwind CSS 開關和切換範例,> 請查看Tailwind UI,這是我們建立的一系列美麗設計及精心打造的元件。
這是支持我們進行此類開源計畫的絕佳方法,讓我們有能力改善計畫內容並讓計畫內容維持良好的狀態。