Checkbox

A control that allows the user to toggle between checked and not checked.

Examples

Basic

PropDefaultTypeDescription
checked-boolean, indeterminateThe controlled checked state of the checkbox. Can be binded with v-model.
defaultChecked-booleanThe checked state of the checkbox when it is initially rendered. Use when you do not need to control its checked state.
disabled-booleanWhen true, prevents the user from interacting with the checkbox.
idrandomId()stringId of the element.
name-stringThe name of the checkbox. Submitted with its owning form as part of a name/value pair.
required-booleanWhen true, indicates that the user must check the checkbox before the owning form can be submitted.
valueonstringThe value given as data when submitted with a name.
label-stringSet the label of the checkbox.
Preview
Code

Color

PropDefaultTypeDescription
colorprimarystringChange the color of the checkbox.
Preview
Code

Form Group

You can use the checkbox component inside the form-group component, or you can use it with the label component.

Preview
Code
Notifications for the conversations you are participating in, or if someone cites you with an @mention. Also for all activity when subscribed to specific events.
Notifications for the conversations you are participating in, or if someone cites you with an @mention. Also for all activity when subscribed to specific events.

You must choose at least one event

Size

Adjust the select size without limits. Use breakpoints (e.g., sm:sm, xs:lg) for responsive sizes or states (e.g., hover:lg, focus:3xl) for state-based sizes.

PropDefaultTypeDescription
sizemdstringAdjust the size of the checkbox.
Preview
Code

You can also utilize data-[state] to dynamically modify the size of the checkbox based on its state.

Data stateDescription
data-[state=checked]Only apply the class if the checkbox is checked.
data-[state=unchecked]Only apply the class if the checkbox is unchecked.
data-[state=indeterminate]Only apply the class if the checkbox is indeterminate.
Preview
Code

Reverse

PropDefaultTypeDescription
reverse-booleanReverse the position of the checkbox and label.
Preview
Code

Customization

You can customize the checkbox using the una prop and utility classes.

PropDefaultTypeDescription
una.checkboxCheckedIconi-checkstringCustom icon of the checkbox when it is checked.
una.checkboxUncheckedIconnullstringCustom icon of the checkbox when it is unchecked.
una.checkboxIndeterminateIconi-lucide-minusstringCustom icon of the checkbox when it is indeterminate.
Preview
Code

Preview
Code

Preview
Code
Value: [ true, true, true, true ]

Slots

NameDescription
defaultUse this slot to customize the label of the checkbox.
iconUse this slot to customize the icon of the checkbox when it is checked

Presets

shortcuts/checkbox.ts
import type { RuleContext } from '@unocss/core'
import type { Theme } from '@unocss/preset-uno'
import { parseColor } from '@unocss/preset-mini/utils'

type CheckboxPrefix = 'checkbox'

export const staticCheckbox: Record<`${CheckboxPrefix}-${string}` | CheckboxPrefix, string> = {
  // base
  'checkbox': 'checkbox-primary text-md w-1em h-1em shrink-0 rounded-sm ring-offset-base focus-visible:outline-none disabled:n-disabled border border-brand bg-brand text-inverted focus-visible:(ring-2 ring-brand ring-offset-2) data-[state=unchecked]:(bg-base text-base)',
  'checkbox-label': 'block',
  'checkbox-reverse': 'flex-row-reverse',

  // wrappers
  'checkbox-wrapper': 'gap-x-3 relative inline-flex items-center hover:cursor-pointer',

  // icon
  'checkbox-indicator': 'flex items-center justify-center h-full w-full data-[state=unchecked]:opacity-0 transition-base opacity-100 text-inverted',
  'checkbox-icon-base': 'w-1em h-1em',
  'checkbox-checked-icon': 'i-check',
  'checkbox-unchecked-icon': '',
  'checkbox-indeterminate-icon': 'i-lucide-minus',
}

export const dynamicCheckbox = [
  [/^checkbox-(.*)$/, ([, body]: string[], { theme }: RuleContext<Theme>) => {
    const color = parseColor(body, theme)
    if ((color?.cssColor?.type === 'rgb' || color?.cssColor?.type === 'rgba') && color.cssColor.components)
      return `n-${body}-600 dark:n-${body}-500`
  }],
]

export const checkbox = [
  ...dynamicCheckbox,
  staticCheckbox,
]

Props

types/checkbox.ts
import type { CheckboxIndicatorProps, CheckboxRootProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import type { NLabelProps } from './label'

interface BaseExtensions {
  class?: HTMLAttributes['class']
}

export interface NCheckboxProps extends CheckboxRootProps, NLabelProps, BaseExtensions {

  /**
   * Allows you to add `UnaUI` checkbox preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   */
  checkbox?: string
  /**
   * Display label text.
   *
   * @default null
   */
  label?: string
  /**
   * Allows you to change the size of the checkbox.
   *
   * @default size="sm"
   *
   * @example
   * size="sm" | size="2cm" | size="2rem" | size="2px"
   */
  size?: string
  /**
   * Switch the position of label and checkbox.
   */
  reverse?: boolean
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/checkbox.ts
   */
  /**
   * Force mount the indicator component.
   *
   * @default true
   */
  forceMount?: CheckboxIndicatorProps['forceMount']

  // subcomponents
  _checkboxIndicator?: CheckboxIndicatorProps
  _label?: NLabelProps

  una?: {
    checkbox?: HTMLAttributes['class']
    checkboxWrapper?: HTMLAttributes['class']
    checkboxLabel?: HTMLAttributes['class']
    checkboxIndicator?: HTMLAttributes['class']
    checkboxIconBase?: HTMLAttributes['class']

    checkboxCheckedIcon?: HTMLAttributes['class']
    checkboxUncheckedIcon?: HTMLAttributes['class']
    checkboxIndeterminateIcon?: HTMLAttributes['class']
  }
}

Components

Checkbox.vue
<script setup lang="ts">
import type { CheckboxRootEmits } from 'radix-vue'
import type { NCheckboxProps } from '../../types'
import { reactivePick } from '@vueuse/core'
import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'
import { computed } from 'vue'
import { cn, randomId } from '../../utils'
import Icon from '../elements/Icon.vue'
import Label from '../elements/Label.vue'

const props = withDefaults(defineProps<NCheckboxProps>(), {
  forceMount: true,
})
const emits = defineEmits<CheckboxRootEmits>()

const delegatedProps = reactivePick(props, [
  'checked',
  'defaultChecked',
  'disabled',
  'id',
  'name',
  'required',
  'value',
  'size',
])

const forwarded = useForwardPropsEmits(delegatedProps, emits)

const id = computed(() => props.id ?? randomId('checkbox'))
</script>

<template>
  <div
    :class="cn(
      'checkbox-wrapper flex',
      una?.checkboxWrapper,
      reverse && 'checkbox-reverse',
    )"
  >
    <CheckboxRoot
      v-bind="forwarded"
      :id="id"
      :class="
        cn(
          'peer checkbox',
          props.class,
        )"
      :checkbox
    >
      <CheckboxIndicator
        :force-mount
        :size
        :class="cn('checkbox-indicator', una?.checkboxIndicator)"
        v-bind="props._checkboxIndicator"
      >
        <slot name="icon">
          <Icon
            :name="props.checked === 'indeterminate'
              ? props.una?.checkboxIndeterminateIcon ?? 'checkbox-indeterminate-icon'
              : props.checked
                ? props.una?.checkboxCheckedIcon ?? 'checkbox-checked-icon'
                : props.una?.checkboxUncheckedIcon ?? 'checkbox-unchecked-icon'"
            :class="cn('checkbox-icon-base', una?.checkboxIconBase)"
          />
        </slot>
      </CheckboxIndicator>
    </CheckboxRoot>

    <Label
      v-if="$slots.default || label"
      :for="props.for || id"
      :class="cn('checkbox-label', una?.checkboxLabel)"
      v-bind="props._label"
    >
      <slot>
        {{ label }}
      </slot>
    </Label>
  </div>
</template>