Admin 元件

Checkbox

參考API
核取方塊。單選、多選、不定態(indeterminate)。

安裝

Terminal
pnpm dlx shadcn-vue add @admin/checkbox
import {  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 const​const 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

名稱型別預設值說明
classClassValue—根元素之自訂 class
idstring | undefined—為內部 input 提供自訂 `id`;未指定時自動產生

Slots

名稱Bindings說明
default{}—

admin-checkbox-group

Props

名稱型別預設值說明
classClassValue—根元素之自訂 class
defaultValueTValue[] | undefined—The value of the checkbox when it is initially rendered. Use when you do not need to control its value.
modelValueTValue[] | undefined—The controlled value of the checkbox. Can be binded with v-model.
rovingFocusboolean | undefined—When `false`, navigating through the items using arrow keys will be disabled.
disabledboolean | undefined—When `true`, prevents the user from interacting with the checkboxes
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
asChildboolean | 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.
dirDirection$5 | undefined—The direction of navigation between items.
orientationOrientation$1 | undefined—The orientation of the group. Mainly so arrow navigation is done accordingly (left & right vs. up & down)
loopboolean | undefinedfalseWhether keyboard navigation should loop around
namestring | undefined—The name of the field. Submitted with its owning form as part of a name/value pair.
requiredboolean | undefined—When `true`, indicates that the user must set the value before the owning form can be submitted.

Events

名稱Payload說明
update:modelValueTValue[]—

Slots

名稱Bindings說明
default{}—

admin-checkbox-input

Props

名稱型別預設值說明
defaultValueboolean | "indeterminate" | undefined—The value of the checkbox when it is initially rendered. Use when you do not need to control its value.
modelValueboolean | "indeterminate" | null | undefined—The controlled value of the checkbox. Can be binded with v-model.
disabledboolean | undefined—When `true`, prevents the user from interacting with the checkbox
valueAcceptableValue | undefined"on"The value given as data when submitted with a `name`.
idstring | undefined—Id of the element
trueValueboolean | undefined—The value used when the checkbox is checked. Defaults to `true`.
falseValueboolean | undefined—The value used when the checkbox is unchecked. Defaults to `false`.
asChildboolean | 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.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
namestring | undefined—The name of the field. Submitted with its owning form as part of a name/value pair.
requiredboolean | undefined—When `true`, indicates that the user must set the value before the owning form can be submitted.
classClassValue—根元素之自訂 class
isErrorboolean | undefined—設為 `true` 時套用 `aria-invalid` 與錯誤態樣式

Events

名稱Payload說明
update:modelValueboolean | "indeterminate"—

Slots

名稱Bindings說明
icon{ modelValue: boolean | "indeterminate"; state: boolean | "indeterminate"; }自訂指示圖示;接收 CheckboxRoot 之 slot scope props(`modelValue` 與 `state`)

admin-checkbox-label

Props

名稱型別預設值說明
classClassValue—根元素之自訂 class

Slots

名稱Bindings說明
default{}—

更新紀錄

  • feat: 新增 admin-checkbox-group 型別安全群組元件57342ea
  • fix: 修正 error 邊框被 focus/open/checked 蓋過dfbeab5
  • fix: indeterminate icon 改讀 slot state 並補正 slot 型別44cea15