安裝
Terminal
pnpm dlx shadcn-vue add @admin/checkboximport { AdminCheckbox, AdminCheckboxGroup, AdminCheckboxInput, AdminCheckboxLabel,} from '@/components/admin/checkbox'用法
<script setup lang="ts">import { ref } from 'vue'import { AdminCheckbox, AdminCheckboxInput, AdminCheckboxLabel } from '@/components/admin/checkbox'const checked = ref<boolean | 'indeterminate'>(false)</script><template> <admin-checkbox> <admin-checkbox-input v-model="checked" /> <admin-checkbox-label>Accept terms</admin-checkbox-label> </admin-checkbox></template>場景
多選群組
以 admin-checkbox-group 包住多個 admin-checkbox(各 input 帶 value),v-model 以陣列承接被選中的 value,勾選同步由底層 CheckboxGroupRoot 處理。
<script setup lang="ts">import { ref } from 'vue'import { AdminCheckbox, AdminCheckboxGroup, AdminCheckboxInput, AdminCheckboxLabel} from '@/components/admin/checkbox'const options = [ { label: '接收電子報', value: 'newsletter' }, { label: '接收推播通知', value: 'push' }, { label: '接收簡訊提醒', value: 'sms' }]const selected = ref<string[]>(['newsletter'])</script><template> <admin-checkbox-group v-model="selected"> <admin-checkbox v-for="opt in options" :key="opt.value"> <admin-checkbox-input :value="opt.value" /> <admin-checkbox-label>{{ opt.label }}</admin-checkbox-label> </admin-checkbox> </admin-checkbox-group></template>Indeterminate(不定態)
父層 checkbox 依子項目狀態在 true / false / 'indeterminate' 三態間切換。
<script setup lang="ts">import { computed, ref } from 'vue'import { AdminCheckbox, AdminCheckboxInput, AdminCheckboxLabel } from '@/components/admin/checkbox'const items = ref<Array<{ label: string; checked: boolean | 'indeterminate' }>>([ { label: '選項 A', checked: true }, { label: '選項 B', checked: false }, { label: '選項 C', checked: true }])const allChecked = computed<boolean | 'indeterminate'>(() => { const count = items.value.filter((i) => i.checked).length if (count === 0) { return false } if (count === items.value.length) { return true } return 'indeterminate'})function toggleAll(v: boolean | 'indeterminate') { const next = v === true items.value.forEach((i) => (i.checked = next))}</script><template> <div class="flex flex-col gap-2"> <admin-checkbox> <admin-checkbox-input :model-value="allChecked" @update:model-value="toggleAll" /> <admin-checkbox-label>全選 / 反選</admin-checkbox-label> </admin-checkbox> <div class="ml-5 flex flex-col gap-2"> <admin-checkbox v-for="item in items" :key="item.label"> <admin-checkbox-input v-model="item.checked" /> <admin-checkbox-label>{{ item.label }}</admin-checkbox-label> </admin-checkbox> </div> </div></template>錯誤狀態
<script setup lang="ts">import { ref } from 'vue'import { AdminCheckbox, AdminCheckboxInput, AdminCheckboxLabel } from '@/components/admin/checkbox'const unchecked = ref<boolean | 'indeterminate'>(false)const checked = ref<boolean | 'indeterminate'>(true)</script><template> <div class="flex flex-col gap-3"> <admin-checkbox> <admin-checkbox-input v-model="unchecked" is-error /> <admin-checkbox-label>未勾選 + error</admin-checkbox-label> </admin-checkbox> <admin-checkbox> <admin-checkbox-input v-model="checked" is-error /> <admin-checkbox-label>已勾選 + error</admin-checkbox-label> </admin-checkbox> </div></template>Type-safe 封裝
AdminCheckboxGroup 已是 generic(T extends AcceptableValue),以較嚴的 ref 綁定 v-model 即可收斂為選項 value 的 literal union 陣列。若要讓 value 與清單對齊,可自行封裝:傳入 options(建議加 as const),由封裝元件以 options 為單一事實來源渲染各選項。
如此 options 即聯集來源,各選項的 value 結構上不可能越界;型別安全落在 v-model 與 defaultValue 必須對齊 options 的 value union(元素型別)。
此食譜刻意精簡;需要時可自行 fork 擴充。封裝元件僅為文件示範,不屬 registry 安裝產物。
TypedAdminCheckboxGroup.vue
<script setup lang="ts" generic=" TOptions extends ReadonlyArray<{ value: AcceptableValue label: string disabled?: boolean }> ">import type { AcceptableValue } from 'reka-ui'import type { AdminCheckboxGroupEmits, AdminCheckboxGroupProps } from '@/components/admin/checkbox'import { reactiveOmit } from '@vueuse/core'import { useForwardPropsEmits } from 'reka-ui'import { AdminCheckbox, AdminCheckboxGroup, AdminCheckboxInput, AdminCheckboxLabel} from '@/components/admin/checkbox'type TValue = TOptions[number]['value']const props = defineProps<AdminCheckboxGroupProps<TValue> & { options: TOptions }>()const emits = defineEmits<AdminCheckboxGroupEmits<TValue>>()const delegatedProps = reactiveOmit(props, 'options')const forwarded = useForwardPropsEmits(delegatedProps, emits)</script><template> <admin-checkbox-group v-bind="forwarded"> <admin-checkbox v-for="(option, index) in props.options" :key="`${option.value}-${index}`"> <admin-checkbox-input :disabled="option.disabled" :value="option.value" /> <admin-checkbox-label>{{ option.label }}</admin-checkbox-label> </admin-checkbox> </admin-checkbox-group></template>需開啟 strictVModel
型別檢查需開啟 strictVModel(若已開啟 strictTemplates 則已包含)。設定見 Type-safe。下列同時含合法綁定與刻意錯誤綁定;錯誤處以 @vue-expect-error 標示。
<script setup lang="ts">import { ref } from 'vue'import TypedAdminCheckboxGroup from './typed-admin-checkbox-group-demo.vue'const options = [ { value: 'newsletter', label: '接收電子報' }, { value: 'push', label: '接收推播通知' }, { value: 'sms', label: '接收簡訊提醒' }] as constconst selected = ref<(typeof options)[number]['value'][]>(['newsletter'])const wrong = ref(['unknown'])const wrongDefault = ['unknown']</script><template> <div class="flex w-full max-w-md flex-col gap-6"> <typed-admin-checkbox-group v-model="selected" :options="options" /> <!-- @vue-expect-error value 不在 options 的 value union 內 --> <typed-admin-checkbox-group v-model="wrong" :options="options" /> <!-- @vue-expect-error defaultValue 不在 options 的 value union 內 --> <typed-admin-checkbox-group :default-value="wrongDefault" :options="options" /> </div></template>API 參考
組成
<template> <admin-checkbox-group v-model="selected"> <admin-checkbox v-for="opt in options" :key="opt.value"> <admin-checkbox-input :value="opt.value" /> <admin-checkbox-label>{{ opt.label }}</admin-checkbox-label> </admin-checkbox> </admin-checkbox-group></template>單顆 checkbox 不需群組時,直接以 v-model 綁定 input:
<template> <admin-checkbox> <admin-checkbox-input v-model="checked" /> <admin-checkbox-label>標籤文字</admin-checkbox-label> </admin-checkbox></template>admin-checkbox
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
id | string | undefined | — | 為內部 input 提供自訂 `id`;未指定時自動產生 |
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
default | {} | — |
admin-checkbox-group
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
defaultValue | TValue[] | undefined | — | The value of the checkbox when it is initially rendered. Use when you do not need to control its value. |
modelValue | TValue[] | undefined | — | The controlled value of the checkbox. Can be binded with v-model. |
rovingFocus | boolean | undefined | — | When `false`, navigating through the items using arrow keys will be disabled. |
disabled | boolean | undefined | — | When `true`, prevents the user from interacting with the checkboxes |
as | globalThis.Component | AsTag | undefined | "div" | The element or component this component should render as. Can be overwritten by `asChild`. |
asChild | boolean | undefined | — | Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
dir | Direction$5 | undefined | — | The direction of navigation between items. |
orientation | Orientation$1 | undefined | — | The orientation of the group. Mainly so arrow navigation is done accordingly (left & right vs. up & down) |
loop | boolean | undefined | false | Whether keyboard navigation should loop around |
name | string | undefined | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | undefined | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
Events
| 名稱 | Payload | 說明 |
|---|---|---|
update:modelValue | TValue[] | — |
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
default | {} | — |
admin-checkbox-input
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
defaultValue | boolean | "indeterminate" | undefined | — | The value of the checkbox when it is initially rendered. Use when you do not need to control its value. |
modelValue | boolean | "indeterminate" | null | undefined | — | The controlled value of the checkbox. Can be binded with v-model. |
disabled | boolean | undefined | — | When `true`, prevents the user from interacting with the checkbox |
value | AcceptableValue | undefined | "on" | The value given as data when submitted with a `name`. |
id | string | undefined | — | Id of the element |
trueValue | boolean | undefined | — | The value used when the checkbox is checked. Defaults to `true`. |
falseValue | boolean | undefined | — | The value used when the checkbox is unchecked. Defaults to `false`. |
asChild | boolean | undefined | — | Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
as | globalThis.Component | AsTag | undefined | "div" | The element or component this component should render as. Can be overwritten by `asChild`. |
name | string | undefined | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | undefined | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
class | ClassValue | — | 根元素之自訂 class |
isError | boolean | undefined | — | 設為 `true` 時套用 `aria-invalid` 與錯誤態樣式 |
Events
| 名稱 | Payload | 說明 |
|---|---|---|
update:modelValue | boolean | "indeterminate" | — |
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
icon | { modelValue: boolean | "indeterminate"; state: boolean | "indeterminate"; } | 自訂指示圖示;接收 CheckboxRoot 之 slot scope props(`modelValue` 與 `state`) |
admin-checkbox-label
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
default | {} | — |