Checkbox
A checkbox with a third, indeterminate state, for a choice a form submits.
Checkbox is a tri-state checkbox that takes part in forms. Useful wherever a
choice should only count once the form is submitted; for a setting that applies
immediately, use Switch.
<template>
<div class="flex flex-col gap-3">
<Field.Root
v-for="option in options"
:key="option.name"
class="flex items-start gap-3"
:options="{ disabled: option.disabled, name: option.name }"
>
<Checkbox.Root
v-model="option.checked"
v-model:indeterminate="option.indeterminate"
:class="box"
>
<Checkbox.Indicator class="block size-[0.9375rem]">
<svg viewBox="0 0 18 18" fill="currentColor" aria-hidden="true">
<path v-if="option.indeterminate" :d="indeterminate" />
<path v-else :d="check" />
</svg>
</Checkbox.Indicator>
</Checkbox.Root>
<Field.Label :class="label">{{ option.label }}</Field.Label>
</Field.Root>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Checkbox } from '@maas/mirror/vue/Checkbox'
import { Field } from '@maas/mirror/vue/Field'
const box = [
'flex size-5 items-center justify-center border-2 border-surface',
'rounded-component-compact-md text-accent-on-solid',
'transition-all duration-100 ease-linear',
'outline-4 outline-transparent focus-visible:focus-ring',
'active:border-primary-subtle',
'data-[state=checked]:bg-accent-solid data-[state=indeterminate]:bg-accent-solid',
'data-[state=checked]:border-[transparent] data-[state=indeterminate]:border-[transparent]',
'data-[state=checked]:active:bg-accent-solid-active',
'data-[state=indeterminate]:active:bg-accent-solid-active',
'data-[disabled=true]:border-disabled-subtle',
'data-[disabled=true]:data-[state=checked]:bg-disabled-solid',
'data-[disabled=true]:text-disabled-on-solid',
].join(' ')
const label = [
'type-component-xs text-surface translate-y-[0.1rem] [--mirror-label-cursor:pointer]',
'data-[disabled=true]:text-disabled-solid',
].join(' ')
const check =
'M13.6875 5.1875C13.875 5 14.1042 4.90625 14.375 4.90625C14.6458 4.90625 14.875 5 15.0625 5.1875C15.25 5.375 15.3438 5.60417 15.3438 5.875C15.3438 6.14583 15.25 6.375 15.0625 6.5625L7.96875 13.6562C7.63542 13.9896 7.22917 14.1562 6.75 14.1562C6.27083 14.1562 5.86458 13.9896 5.53125 13.6562L2.9375 11.0625C2.75 10.875 2.65625 10.6458 2.65625 10.375C2.65625 10.1042 2.75 9.875 2.9375 9.6875C3.125 9.5 3.35417 9.40625 3.625 9.40625C3.89583 9.40625 4.125 9.5 4.3125 9.6875L6.90625 12.2812C6.86458 12.2396 6.8125 12.2188 6.75 12.2188C6.6875 12.2188 6.63542 12.2396 6.59375 12.2812L13.6875 5.1875Z'
const indeterminate =
'M14.0313 8.03125C14.3021 8.03125 14.5312 8.125 14.7187 8.3125C14.9062 8.5 15 8.72917 15 9C15 9.27083 14.9062 9.5 14.7187 9.6875C14.5312 9.875 14.3021 9.96875 14.0313 9.96875H3.96875C3.69792 9.96875 3.46875 9.875 3.28125 9.6875C3.09375 9.5 3 9.27083 3 9C3 8.72917 3.09375 8.5 3.28125 8.3125C3.46875 8.125 3.69792 8.03125 3.96875 8.03125H14.0313Z'
const options = ref([
{
name: 'terms',
label: 'Accept the terms',
checked: true,
indeterminate: false,
disabled: false,
},
{
name: 'digest',
label: 'Weekly digest',
checked: false,
indeterminate: true,
disabled: false,
},
{
name: 'beta',
label: 'Beta features',
checked: false,
indeterminate: false,
disabled: true,
},
])
</script>
Usage guidelines
- Make sure the checkbox has an accessible name, either through a
Labelinside aFieldor anaria-labelon the root.must - Bind the mixed state with
v-model:indeterminate. Passed as a plain prop it is controlled, so activating the checkbox emits but leaves the mixed state on screen.should options.readOnlynever reaches the hidden input, so a read-only checkbox still submits its value. Useoptions.disabledto leave it out of the submission.should