<script setup lang="ts">
import { ref } from 'vue'
import { CheckboxGroup } from '@hina-ui/vue'
const types = ref(['gal', 'ln'])
const options = [
{ value: 'gal', label: 'Galgame' },
{ value: 'ln', label: '轻小说' },
{ value: 'manga', label: '漫画' },
]
</script>
<template>
<CheckboxGroup v-model="types" :options="options" aria-label="作品类型" />
</template>
vue
用法
import { CheckboxGroup } from '@hina-ui/vue'
ts
复选框组按 options 渲染一列 Checkbox,v-model 绑定已选值的数组,选项的类型见 Select。未声明的属性都会传给根元素,应当用 aria-label 或者 aria-labelledby 给整组命名。
当前值:[ "mail" ]
<script setup lang="ts">
import { ref } from 'vue'
import { CheckboxGroup, Stack, Text } from '@hina-ui/vue'
const channels = ref(['mail'])
const options = [
{ value: 'mail', label: '邮件' },
{ value: 'push', label: '站内推送' },
{ value: 'sms', label: '短信' },
]
</script>
<template>
<Stack gap="sm">
<CheckboxGroup v-model="channels" :options="options" aria-label="通知方式" />
<Text size="sm" tone="muted">当前值:{{ channels }}</Text>
</Stack>
</template>
vue
示例
横排
orientation 为 horizontal 时选项横向排列,放不下时折行。
<script setup lang="ts">
import { ref } from 'vue'
import { CheckboxGroup } from '@hina-ui/vue'
const days = ref(['sat', 'sun'])
const options = [
{ value: 'mon', label: '周一' },
{ value: 'wed', label: '周三' },
{ value: 'fri', label: '周五' },
{ value: 'sat', label: '周六' },
{ value: 'sun', label: '周日' },
]
</script>
<template>
<CheckboxGroup v-model="days" :options="options" orientation="horizontal" aria-label="更新日" />
</template>
vue
描述
选项的 description 显示在文字下方。
<script setup lang="ts">
import { ref } from 'vue'
import { CheckboxGroup } from '@hina-ui/vue'
const scopes = ref(['read'])
const options = [
{ value: 'read', label: '读取', description: '查看收藏与阅读进度' },
{ value: 'write', label: '写入', description: '修改收藏与评分' },
{ value: 'admin', label: '管理', description: '管理令牌与授权范围' },
]
</script>
<template>
<CheckboxGroup v-model="scopes" :options="options" aria-label="授权范围" />
</template>
vue
设置行
使用 control-placement="end" 将控件放到文案末端,配合 block 撑满容器宽度。说明始终位于标题下方;start 和 end 会跟随文字方向。启用 block 后,纵向选项各自撑满一行,横向选项等分行宽。orientation 仍表示多个选项的排列方向。
<script setup lang="ts">
import { ref } from 'vue'
import { CheckboxGroup } from '@hina-ui/vue'
const scopes = ref(['read'])
const options = [
{ value: 'read', label: '读取', description: '查看收藏与阅读进度' },
{ value: 'write', label: '写入', description: '修改收藏与评分' },
{ value: 'admin', label: '管理', description: '管理令牌与授权范围' },
]
</script>
<template>
<CheckboxGroup
v-model="scopes"
control-placement="end"
block
:options="options"
aria-label="授权范围"
/>
</template>
vue
尺寸
size 下发到每个复选框。
<script setup lang="ts">
import { CheckboxGroup, Inline } from '@hina-ui/vue'
const options = [
{ value: 'gal', label: 'Galgame' },
{ value: 'ln', label: '轻小说' },
]
</script>
<template>
<Inline gap="lg" align="start">
<CheckboxGroup size="sm" :options="options" :model-value="['gal']" aria-label="小号" />
<CheckboxGroup size="md" :options="options" :model-value="['gal']" aria-label="中号" />
<CheckboxGroup size="lg" :options="options" :model-value="['gal']" aria-label="大号" />
</Inline>
</template>
vue
状态
选项上的 disabled 只禁用该项,组上的 disabled 禁用整组;invalid 落到每个方框。
<script setup lang="ts">
import { CheckboxGroup, Inline } from '@hina-ui/vue'
const options = [
{ value: 'gal', label: 'Galgame' },
{ value: 'ln', label: '轻小说' },
{ value: 'manga', label: '漫画', disabled: true },
]
</script>
<template>
<Inline gap="lg" align="start">
<CheckboxGroup :options="options" :model-value="['gal']" aria-label="含禁用项" />
<CheckboxGroup disabled :options="options" :model-value="['gal']" aria-label="整组禁用" />
<CheckboxGroup invalid :options="options" :model-value="[]" aria-label="校验未通过" />
</Inline>
</template>
vue
定制内容
option 插槽定制每一项的文字。
组件从 options 推断完整选项类型,插槽中的 option 保留额外字段及其类型;v-model 仍绑定选项的 value 数组。类型定义见 Select。
<script setup lang="ts">
import { ref } from 'vue'
import { BookOpen, Gamepad2, Images } from '@lucide/vue'
import { CheckboxGroup, Inline } from '@hina-ui/vue'
const icons = { gal: Gamepad2, ln: BookOpen, manga: Images }
const types = ref(['gal'])
const options = [
{ value: 'gal', label: 'Galgame' },
{ value: 'ln', label: '轻小说' },
{ value: 'manga', label: '漫画' },
]
</script>
<template>
<CheckboxGroup v-model="types" :options="options" aria-label="作品类型">
<template #option="{ option }">
<Inline as="span" gap="xs" align="center">
<component :is="icons[option.value as keyof typeof icons]" class="text-muted size-4" />
{{ option.label }}
</Inline>
</template>
</CheckboxGroup>
</template>
vue
在表单中
放进 FormField 后,标签通过 aria-labelledby 关联到整组,说明与错误信息由字段渲染;校验规则与提交交给 Form。
<script setup lang="ts">
import { reactive, ref } from 'vue'
import * as v from 'valibot'
import { Button, CheckboxGroup, Form, FormField, Text } from '@hina-ui/vue'
const options = [
{ label: '游戏', value: 'game' },
{ label: '小说', value: 'novel' },
{ label: '漫画', value: 'manga' },
{ label: '动画', value: 'anime' },
]
const schema = v.object({
interests: v.pipe(
v.array(v.string('请选择兴趣')),
v.minLength(1, '至少选择一项'),
v.maxLength(2, '最多选择两项'),
),
})
const values = reactive({ interests: [] as Array<string | number> })
const saved = ref('')
async function save(data: unknown) {
await new Promise(resolve => setTimeout(resolve, 600))
saved.value = JSON.stringify(data)
}
</script>
<template>
<Form v-slot="{ submitting }" :values="values" :rules="schema" class="w-80" @submit="save">
<FormField name="interests" label="兴趣" description="选一到两项" required>
<CheckboxGroup v-model="values.interests" :options="options" />
</FormField>
<Button type="submit" :loading="submitting" class="self-start">保存</Button>
<Text v-if="saved" tone="muted" size="sm">已保存:{{ saved }}</Text>
</Form>
</template>
vue
行为
- 点选把值加入数组,再点移除,数组顺序与点选顺序一致。
- 每个复选框都是独立的 Tab 停靠点,空格切换焦点所在项,方向键不移动焦点,与原生复选框组一致。
无障碍
- 根元素是
role="group",通过aria-label或者aria-labelledby命名;每一项沿用Checkbox的语义。
API
Props
T extends SelectOption 从 options 推断,默认是 SelectOption。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | Array<string | number> | [] | 已选值 |
options | T[] | — | 选项,类型见 Select |
orientation | 'vertical' | 'horizontal' | 'vertical' | 排列方向 |
size | 'sm' | 'md' | 'lg' | 'md' | 每个复选框的尺寸 |
controlPlacement | 'start' | 'end' | 'start' | 控件相对于文案的位置 |
block | boolean | false | 整组撑满,横向选项等分宽度 |
disabled | boolean | false | 是否禁用整组 |
invalid | boolean | false | 是否处于校验未通过状态 |
class | string | — | 追加至根元素的类名 |
插槽
| 插槽 | 参数 | 说明 |
|---|---|---|
option | { option: T } | 每一项的文字 |
事件
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: Array<string | number> | 已选值变化 |