Checkbox 复选框

勾选一项,或者从多项中勾选若干。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Checkbox } from '@hina-ui/vue'

  const notify = ref(true)
</script>

<template>
  <Checkbox v-model="notify">有新章节时通知我</Checkbox>
</template>
vue

用法

import { Checkbox } from '@hina-ui/vue'
ts

复选框把方框与它的文字合成一个可点击的整体。v-model 绑定布尔值,值为 'indeterminate' 时显示半选。默认插槽是文字,点文字与点方框都会切换。未声明的属性都会传给内部的方框元素。

当前值:false

<script setup lang="ts">
  import { ref } from 'vue'
  import { Checkbox, Stack, Text } from '@hina-ui/vue'

  const remember = ref(false)
</script>

<template>
  <Stack gap="sm">
    <Checkbox v-model="remember">记住登录状态</Checkbox>
    <Text size="sm" tone="muted">当前值:{{ remember }}</Text>
  </Stack>
</template>
vue

示例

描述

description 在文字下方补一行说明,字号比文字小一档。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Checkbox } from '@hina-ui/vue'

  const weekly = ref(true)
</script>

<template>
  <Checkbox v-model="weekly" description="每周一发送本周的更新汇总,可以随时退订。">
    订阅周报
  </Checkbox>
</template>
vue

设置行

使用 control-placement="end" 将控件放到文案末端,配合 block 撑满容器宽度。说明始终位于标题下方;start 和 end 会跟随文字方向。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Checkbox } from '@hina-ui/vue'

  const weekly = ref(true)
</script>

<template>
  <Checkbox
    v-model="weekly"
    control-placement="end"
    block
    description="每周一发送本周的更新汇总,可以随时退订。"
  >
    订阅周报
  </Checkbox>
</template>
vue

半选

值为 'indeterminate' 时显示横线。常见的用法是「全选」:子项部分选中时父项半选,点击父项后全部选中。

<script setup lang="ts">
  import { computed, ref } from 'vue'
  import { Checkbox, Stack } from '@hina-ui/vue'

  const types = ['Galgame', '轻小说', '漫画']
  const picked = ref(['Galgame'])

  const all = computed<boolean | 'indeterminate'>({
    get: () =>
      picked.value.length === 0
        ? false
        : picked.value.length === types.length
          ? true
          : 'indeterminate',
    set: value => {
      picked.value = value === true ? [...types] : []
    },
  })

  function toggle(type: string, on: boolean | 'indeterminate') {
    picked.value = on === true ? [...picked.value, type] : picked.value.filter(t => t !== type)
  }
</script>

<template>
  <Stack gap="sm">
    <Checkbox v-model="all">全部类型</Checkbox>
    <Stack gap="sm" class="ps-6">
      <Checkbox
        v-for="type in types"
        :key="type"
        :model-value="picked.includes(type)"
        @update:model-value="toggle(type, $event)"
      >
        {{ type }}
      </Checkbox>
    </Stack>
  </Stack>
</template>
vue

尺寸

size 有 sm、md、lg 三档,方框分别为 14、16、18 像素,文字随档位变化。

<script setup lang="ts">
  import { Checkbox, Stack } from '@hina-ui/vue'
</script>

<template>
  <Stack gap="sm">
    <Checkbox size="sm" model-value>小号</Checkbox>
    <Checkbox size="md" model-value>中号</Checkbox>
    <Checkbox size="lg" model-value>大号</Checkbox>
  </Stack>
</template>
vue

状态

invalid 把方框的边框改为警示色;disabled 禁用整个控件。

<script setup lang="ts">
  import { Checkbox, Stack } from '@hina-ui/vue'
</script>

<template>
  <Stack gap="sm">
    <Checkbox invalid>我已阅读并同意用户协议</Checkbox>
    <Checkbox disabled>已禁用</Checkbox>
    <Checkbox disabled model-value>已禁用且选中</Checkbox>
  </Stack>
</template>
vue

仅方框

没有文字时只渲染方框,此时必须用 aria-label 命名。表格的行选择就是这种情形。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Checkbox, Inline } from '@hina-ui/vue'

  const rows = ref([true, false, false])
</script>

<template>
  <Inline gap="sm">
    <Checkbox
      v-for="(_, index) in rows"
      :key="index"
      v-model="rows[index]"
      :aria-label="`选择第 ${index + 1} 行`"
    />
  </Inline>
</template>
vue

在表单中

放进 FormField 后,错误信息由字段渲染并关联到复选框;校验规则与提交交给 Form。复选框自带文字,字段不必再写标签。

<script setup lang="ts">
  import { reactive, ref } from 'vue'
  import * as v from 'valibot'
  import { Button, Checkbox, Form, FormField, Text } from '@hina-ui/vue'

  const schema = v.object({
    agreed: v.literal(true, '请先阅读并同意服务条款'),
  })

  const values = reactive({ agreed: false as boolean | 'indeterminate' })
  const saved = ref(false)

  async function save() {
    await new Promise(resolve => setTimeout(resolve, 600))
    saved.value = true
  }
</script>

<template>
  <Form v-slot="{ submitting }" :values="values" :rules="schema" class="w-80" @submit="save">
    <FormField name="agreed">
      <Checkbox v-model="values.agreed">我已阅读并同意服务条款</Checkbox>
    </FormField>
    <Button type="submit" :loading="submitting" class="self-start">注册</Button>
    <Text v-if="saved" tone="muted" size="sm">已注册。</Text>
  </Form>
</template>
vue

行为

  • 点击文字或者方框都会切换。键盘 Tab 落在方框上,空格切换,Enter 不切换,与原生复选框一致。
  • 半选状态点击一次变为选中。
  • 悬停整个控件时方框落墨,按下时加深;勾以缩放淡入进场,取消时淡出。

无障碍

  • 方框是 role="checkbox" 的按钮,带 aria-checked,半选为 mixed。根元素是 label,文字即名称。
  • 没有文字时通过 aria-label 或者 aria-labelledby 命名。
  • invalid 会同时设置 aria-invalid。

API

Props

属性
类型
默认值
说明
modelValue
boolean | 'indeterminate'
false
是否选中,'indeterminate' 为半选
size
'sm' | 'md' | 'lg'
'md'
尺寸
description
string
—
文字下方的说明
controlPlacement
'start' | 'end'
'start'
控件相对于文案的位置
block
boolean
false
整行撑满容器宽度
disabled
boolean
false
是否禁用
invalid
boolean
false
是否处于校验未通过状态
class
string
—
追加至根元素的类名

插槽

插槽
参数
说明
default
—
文字

事件

事件
参数
说明
update:modelValue
value: boolean
值变化时