核取方塊

核取方塊提供與本機 HTML 核取方塊相同的功能,但沒有任何樣式設定,讓你可以自由設計任何你想要的樣式。

To get started, install Headless UI via npm

npm install @headlessui/react

核取方塊是用 Checkbox 元件建構的。您可以點選元件或是在聚焦時按空白鍵來切換核取方塊。

切換核取方塊會呼叫 onChange 函式,帶有新的 checked 值。

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

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

  return (
    <Checkbox
      checked={enabled}
      onChange={setEnabled}
      className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500"
    >
      {/* Checkmark icon */}
      <svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none">
        <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    </Checkbox>
  )
}

Headless UI 會追蹤每個元件的許多狀態,例如核取方塊是否已勾選、快顯視窗是否開啟或關閉,或功能表中目前由鍵盤聚焦的項目為何。

但是,由於元件預設是 headless 且完全沒有樣式,您無法在 UI 中看到這些資訊,直到您自行提供希望套用於各個狀態的樣式。

調整 Headless UI 元件不同狀態最簡單的方法是使用每個元件公開的 data-* 屬性。

例如,Checkbox 元件公開一個 data-checked 屬性,它會指出核取方塊目前是否已勾選,以及一個 data-disabled 屬性,它會指出核取方塊目前是否已停用。

<!-- Rendered `Checkbox` -->
<span role="checkbox" data-checked data-disabled>
  <!-- ... -->
</span>

使用 CSS 屬性選擇器 來有條件地套用樣式,根據這些資料屬性的存在與否。如果您使用 Tailwind CSS,資料屬性修改器 會讓這件事變得很容易

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

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

  return (
    <Checkbox
      checked={enabled}
      onChange={setEnabled}
className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[checked]:data-[disabled]:bg-gray-500"
>
<svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none">
<path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> ) }

請參閱 元件 API 查看所有可用的資料屬性清單。

每個元件也會透過 渲染道具 公開其目前狀態的資訊,您可以使用它來有條件地套用不同的樣式或渲染不同的內容。

例如,Checkbox 元件公開一個 checked 狀態,它會指出核取方塊目前是否已勾選,以及一個 disabled 狀態,它會指出核取方塊目前是否已停用。

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

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

  return (
    <Checkbox checked={enabled} onChange={setEnabled} as={Fragment}>
{({ checked, disabled }) => (
<span className={clsx( 'block size-4 rounded border',
!checked && 'bg-white',
checked && !disabled && 'bg-blue-500',
checked && disabled && 'bg-gray-500',
disabled && 'cursor-not-allowed opacity-50'
)}
>
<svg className={clsx('stroke-white', checked ? 'opacity-100' : 'opacity-0')} viewBox="0 0 14 14" fill="none">
<path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </span>
)}
</Checkbox> ) }

請參閱 元件 API 查看所有可用的渲染道具清單。

Field 元件包裝 LabelCheckbox,以自動關聯它們並使用產生的 ID

import { useState } from 'react'
import { Checkbox, Field, Label } from '@headlessui/react'
function Example() { const [enabled, setEnabled] = useState(false) return (
<Field className="flex items-center gap-2">
<Checkbox checked={enabled} onChange={setEnabled} className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500" > <svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox>
<Label>Enable beta features</Label>
</Field>
) }

預設上,按一下 Label 將切換 Checkbox,就像標籤對原生 HTML 核取方塊的動作。如果你想讓 Label 不可按,你可以新增一個 passive 道具到 Label 元件

<Label passive>Enable beta features</Label>

在一個 Field 內使用 Description 元件,以自動關聯它與 Checkbox,使用 aria-describedby 屬性

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

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

  return (
<Field>
<Label>Enable beta features</Label>
<Description>This will give you early access to new features we're developing.</Description>
<Checkbox checked={enabled} onChange={setEnabled} className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500" > <svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox>
</Field>
) }

新增 disabled 道具到 Field 元件來停用一個 Checkbox 與它關聯的 LabelDescription

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

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

  return (
<Field disabled>
<Label className="data-[disabled]:opacity-50">Enable beta features</Label> <Description className="data-[disabled]:opacity-50"> This will give you early access to new features we're developing. </Description> <Checkbox checked={enabled} onChange={setEnabled} className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[checked]:data-[disabled]:bg-gray-500" > <svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> </Field> ) }

你也可以在 Field 外面停用一個核取方塊,直接把 disabled 道具新增到 Checkbox 本身即可。

如果你新增 name 道具到你的 Checkbox,一個隱藏的 input 將會渲染,並與核取方塊狀態保持同步。

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

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

  return (
    <form action="/accounts" method="post">
      <Checkbox
        checked={enabled}
        onChange={setEnabled}
name="terms-of-service"
className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500" >
<svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> <button>Submit</button> </form> ) }

這樣你可以用一個核取方塊在一個原生的 HTML <form> 內部,並像你的核取方塊是一個原生的 HTML 表單控制項一樣,做出傳統的表單提交。

預設上,值會是 on 當核取方塊被選中,當核取方塊沒選中時值不存在。

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

你可以在需要時使用 value 道具自訂值

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

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

  return (
    <form action="/accounts" method="post">
      <Checkbox
        checked={enabled}
        onChange={setEnabled}
        name="terms-of-service"
value="accept"
className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500" >
<svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> <button>Submit</button> </form> ) }

當核取方塊被選中時,隱藏的輸入項將使用你的自訂值

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

像是字串的基本值將會渲染為一個包含這個值的單一隱藏輸入項,但是複雜的值像是物件會被編碼成多個輸入項,使用方括號表示法給它們命名。

如果你略過 checked 道具,Headless UI 將會在內部追蹤它的狀態,讓你用它當做 不受控的元件

當不受控時,你可以使用 defaultChecked 道具預設勾選 Checkbox

import { Checkbox } from '@headlessui/react'

function Example() {
  return (
    <form action="/accounts" method="post">
      <Checkbox
defaultChecked={true}
name="terms-of-service" className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500" >
<svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> <button>Submit</button> </form> ) }

這可以簡化你的程式碼,當使用核取方塊 與 HTML 表單一起 或是有 API 的表單用 FormData 而非用 React 的狀態追蹤它的狀態時。

您提供的任何 onChange 屬性仍可在元件值變更時呼叫,以防您需要執行任何副作用,但您不需要使用它來自行追蹤元件狀態。

由於核取方塊通常總是呈現在 DOM(而非像其他元件一樣會掛載/卸載),因此使用簡單的 CSS 轉場通常就足以為您的核取方塊增添動畫效果

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

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

  return (
    <Checkbox
      checked={enabled}
      onChange={setEnabled}
className="group block size-4 rounded border bg-white transition data-[checked]:bg-blue-500"
>
<svg
className="stroke-white opacity-0 transition group-data-[checked]:opacity-100"
viewBox="0 0 14 14" fill="none" >
<path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> ) }

由於 Headless UI 元件沒有渲染,所以也可以與 React 生態系中其他動畫函式庫,例如 Framer MotionReact Spring 搭配使用。

Checkbox 元件預設會渲染 span。請使用 as 屬性,讓元件以不同的元素或您自己的自訂元件渲染。

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

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

  return (
    <Checkbox
as="div"
checked={enabled} onChange={setEnabled} className="group block size-4 rounded border bg-white data-[checked]:bg-blue-500" >
<svg className="stroke-white opacity-0 group-data-[checked]:opacity-100" viewBox="0 0 14 14" fill="none"> <path d="M3 8L6 11L11 3.5" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </svg> </Checkbox> ) }

指令說明

SpaceCheckbox 獲得焦點時

切換核取方塊

EnterCheckbox 獲得焦點時

提交父表單(如果存在)

屬性預設值說明
asspan
字串 | 元件

核取方塊應該要渲染為的元素或元件。

checked
布林

表示核取方塊是否已勾選。

defaultChecked
T

使用非受控元件時的預設勾選值。

onChange
(value: Boolean) => void

當切換核取方塊時調用的函數。

indeterminate
布林

表示核取方塊是否為不確定狀態。

disabledfalse
布林

表示應該要渲染為是否已停用.

autoFocusfalse
布林

表示應該要渲染為初次渲染時是否會獲得焦點。

name
字串

應該要渲染為內使用時使用的名稱

表單。
字串

form應該要渲染為所屬

如若提供 name 但不提供 form,該應該要渲染為將會把其狀態加入最近的祖先 form 元素中。

字串

如於此組件內使用表單時使用的值,如已勾選。

資料屬性呈現 Prop說明
data-checkedchecked

布林

表示應該要渲染為已被勾選。

data-indeterminateindeterminate

布林

表示應該要渲染為是未確定的。

data-disableddisabled

布林

表示應該要渲染為已停用。

data-focusfocus

布林

表示應該要渲染為已被聚焦。

data-hoverhover

布林

表示應該要渲染為已被懸停。

data-activeactive

布林

表示應該要渲染為是處於主動或被按下的狀態。

data-autofocusautofocus

布林

autoFocus prop 是否設為 true

data-changingchanging

布林

勾選狀態是否正在改變中。

checked 狀態改變時,changing 將會在兩個動畫影格中變成 true,可讓您微調轉場效果。

標籤說明及表單控制元件群組在一起。

屬性預設值說明
asdiv
字串 | 元件

核取方塊field的元素或元件。

disabledfalse
布林

欄位是否已停用。

資料屬性呈現 Prop說明
data-disableddisabled

布林

欄位是否已停用。

標籤組件標記表單控制元件。

屬性預設值說明
aslabel
字串 | 元件

核取方塊label的元素或元件。

passivefalse
布林

當此為 true 時,按一下標籤不會對應表單控制元件焦點。

資料屬性呈現 Prop說明
data-disableddisabled

布林

父層 欄位 是否已停用。

說明組件說明表單控制元件。

屬性預設值說明
asp
字串 | 元件

核取方塊description的元素或元件。

資料屬性呈現 Prop說明
data-disableddisabled

布林

父層 欄位 是否已停用。

如您有興趣了解預先設計的 Tailwind CSS 核取方塊組件範例,請查看 Tailwind UI — 由我們建置的一系列設計精美且製作精良的組件。

此為支持我們在類似此等開源專案工作的好方法,並能讓我們提升此等專案並保持良好維護。