๐ŸŸข Checkbox


Basic

use NCheckbox component to create a checkbox.

AttributeTypeDefaultDescription
v-model:checkedboolean indeterminatefalseBind the checkbox to a boolean value.
labelstring''Set the label of the checkbox.
<script setup lang="ts">
const checked = ref(false)
</script>

<template>
  <NCheckbox v-model:checked="checked" label="Checkbox" />
</template>

Indeterminate

checked="indeterminate" - set the checkbox to indeterminate state.

<script setup lang="ts">
const checked = ref<'indeterminate' | boolean>('indeterminate')
</script>

<template>
  <NCheckbox
    v-model:checked="checked"
    label="Indeterminate"
  />
</template>

Color

checkbox="{color}" - change the color of the checkbox.

You can use breakpoints such as sm:red, xs:green to change color based on screen size.

You can use any color provided by the Tailwind CSS color palette, the default is primary. You can also add your own colors to the palette through the Configuration section.
<script setup lang="ts">
const colors = ref([
  {
    checkbox: 'red sm:primary',
    value: true,
  },
  {
    checkbox: 'info',
    value: true,
  },
  {
    checkbox: 'error',
    value: true,
  },
  {
    checkbox: 'warning',
    value: true,
  },
  {
    checkbox: 'success',
    value: true,
  },
  {
    checkbox: 'purple',
    value: true,
  },
  {
    checkbox: 'pink',
    value: true,
  },
  {
    checkbox: 'violet',
    value: true,
  },
  {
    checkbox: 'fuchsia',
    value: true,
  },
  {
    checkbox: 'indigo',
    value: true,
  },
])
</script>

<template>
  <div class="flex flex-wrap gap-4">
    <NCheckbox
      v-for="color in colors"
      :key="color.checkbox"
      v-model:checked="color.value"
      :label="color.checkbox"
      :checkbox="color.checkbox"
    />
  </div>
</template>

Form Group

You can use the NFormGroup component to create a checkbox group for the checkbox,

Read more about the NFormGroup component here.

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

<script setup lang="ts">
const notifications = ref([
  {
    label: 'On github',
    value: false,
    checkbox: 'gray',
  },
  {
    label: 'Email',
    value: false,
    checkbox: 'yellow',
  },
  {
    label: 'Discord',
    value: false,
    checkbox: 'indigo',
  },
])
</script>

<template>
  <div class="flex flex-col space-y-6">
    <!-- Vertical -->
    <NFormGroup
      label="Participating, @mentions and custom"
      description="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."
    >
      <NCheckbox
        v-for="option in notifications"
        :key="option.label"
        v-model:checked="option.value"
        :label="option.label"
        :checkbox="option.checkbox"
      />
    </NFormGroup>

    <NSeparator />

    <!-- Horizontal -->
    <NFormGroup
      required
      message="You must choose at least one event"
      label="Participating, @mentions and custom"
      description="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."
    >
      <div class="flex flex-wrap gap-8">
        <NCheckbox
          v-for="option in notifications"
          :key="option.label"
          v-model:checked="option.value"
          :label="option.label"
          :checkbox="option.checkbox"
        />
      </div>
    </NFormGroup>
  </div>
</template>

Size

size="{size}" - change the size of the checkbox.

You can freely adjust the size of the checkbox using any size imaginable. No limits exist, and you can use data-[state] to adjust the size based on the state of the checkbox.
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.
<script setup lang="ts">
const items = ref([
  {
    label: '0.8cm',
    size: '0.8cm',
    checkbox: 'primary',
    value: true,
  },
  {
    label: 'xs md:2xl',
    size: 'xs md:2xl data-[state=checked]:3xl',
    checkbox: 'blue',
    value: 'indeterminate',
  },
  {
    label: 'sm',
    size: 'sm data-[state=checked]:2xl',
    checkbox: 'green',
    value: true,
  },
  {
    label: 'md',
    size: 'md data-[state=checked]:2xl',
    checkbox: 'purple',
    value: true,
  },
  {
    label: 'lg',
    size: 'lg data-[state=checked]:2xl',
    checkbox: 'red',
    value: true,
  },
])
</script>

<template>
  <div class="flex gap-4">
    <NCheckbox
      v-for="item in items"
      :key="item.size"
      v-model:checked="item.value as boolean | 'indeterminate'"
      v-bind="{
        size: item.size,
        label: item.label,
        checkbox: item.checkbox,
      }"
    />
  </div>
</template>

Disabled

disabled - disable the checkbox.

<script setup lang="ts">
const checkbox = ref()
</script>

<template>
  <div class="flex gap-4">
    <NCheckbox v-model:checked="checkbox" label="Disabled" disabled />

    <NCheckbox v-model:checked="checkbox" label="Not disabled" />
  </div>
</template>

Reverse

reverse - Switch the position of the checkbox and the label.

<script setup lang="ts">
const options = ref([
  { label: 'Checkbox A', value: false },
  { label: 'Checkbox B', value: false },
  { label: 'Checkbox C', value: false },
])
</script>

<template>
  <div class="flex flex-wrap space-x-8">
    <NCheckbox
      v-for="option in options"
      :key="option.label"
      v-model:checked="option.value"
      :label="option.label"
      reverse
    />
  </div>
</template>

Customization

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

You can also globally customize the checkbox preset if you want to have a different default style. See Configuration section for more details.
PropertyTypeDefaultDescription
una.checkboxCheckedIconstringi-checkCustom icon of the checkbox when it is checked.
una.checkboxUncheckedIconstringnullCustom icon of the checkbox when it is unchecked.
una.checkboxIndeterminateIconstringi-lucide-minusCustom icon of the checkbox when it is indeterminate.
<script setup lang="ts">
const options = ref([
  {
    value: true,
    label: '1',
  },
  {
    value: true,
    label: '2',
  },
  {
    value: false,
    label: '3',
  },
])
</script>

<template>
  <div class="flex flex-wrap gap-4">
    <NCheckbox
      v-for="(option, i) in options"
      :key="i"
      v-model:checked="option.value"
      :label="option.label"
      size="xl"
      :una="{
        checkboxCheckedIcon: 'i-tabler-checks',
      }"
    />
  </div>
</template>

<script setup lang="ts">
const options = ref([
  {
    value: true,
    label: '1',
    checkbox: 'green',
    una: {
      checkboxCheckedIcon: 'i-tabler-circle-1-filled',
    },
  },
  {
    value: true,
    label: '2',
    checkbox: 'blue',
    una: {
      checkboxCheckedIcon: 'i-tabler-circle-2-filled',
    },
  },
  {
    value: true,
    label: '3',
    checkbox: 'red',
    una: {
      checkboxCheckedIcon: 'i-tabler-circle-3-filled',
    },
  },
])
</script>

<template>
  <div class="flex flex-wrap gap-4">
    <NCheckbox
      v-for="(option, i) in options"
      :key="i"
      v-model:checked="option.value"
      :checkbox="option.checkbox"
      :label="option.label"
      size="3xl"
      class="rounded-full"
      :una="option.una"
    />
  </div>
</template>

Value: [ true, true, true, true ]
<script setup lang="ts">
const options = ref([
  {
    value: true,
    label: 'Vue',
    class: 'data-[state=checked]:bg-green-500/30 data-[state=checked]:border-green-500',
    checkbox: 'green',
    una: {
      checkboxCheckedIcon: 'i-logos-vue',
      checkboxIndicator: 'data-[state=checked]:scale-150 transition-transform duration-1000',
    },
  },
  {
    value: true,
    label: 'React',
    class: 'data-[state=checked]:bg-blue-500/30 data-[state=checked]:border-blue-500',
    checkbox: 'blue',
    una: {
      checkboxCheckedIcon: 'i-logos-react',
      checkboxIndicator: 'data-[state=checked]:rotate-360 transition-transform duration-1000',
    },
  },
  {
    value: true,
    label: 'Angular',
    class: 'data-[state=checked]:bg-red-500/30 data-[state=checked]:border-red-500',
    checkbox: 'red',
    una: {
      checkboxCheckedIcon: 'i-logos-angular-icon',
      checkboxIndicator: 'data-[state=checked]:scale-120 transition-transform duration-1000',
    },
  },
  {
    value: true,
    label: 'Svelte',
    class: 'data-[state=checked]:bg-orange-500/30 data-[state=checked]:border-orange-500',
    checkbox: 'orange',
    una: {
      checkboxCheckedIcon: 'i-logos-svelte-icon',
      checkboxIndicator: 'data-[state=checked]:scale-120 transition-transform duration-1000',
    },
  },
])

const optionsValue = computed(() => options.value.map(option => option.value))
</script>

<template>
  <div class="flex flex-col space-y-6">
    <span>
      Value: {{ optionsValue }}
    </span>

    <div class="flex flex-wrap gap-4">
      <NCheckbox
        v-for="(option, i) in options"
        :key="i"
        v-model:checked="option.value"
        :checkbox="option.checkbox"
        size="15"
        :label="option.label"
        :class="option.class"
        class="rounded-md"
        :una="option.una"
      />
    </div>
  </div>
</template>

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

Props

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 {
  /**
   * Disable the checkbox.
   */
  disabled?: boolean
  /**
   * Switch the position of label and checkbox.
   */
  reverse?: boolean

  /**
   * 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
  /**
   * Add name attribute to the checkbox.
   *
   * @default null
   */
  name?: string
  /**
   * Manually set the id attribute.
   * By default, the id attribute is generated randomly for accessibility reasons.
   *
   * @default randomId
   */
  id?: 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
  /**
   * `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']
  }
}

Presets

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,
]

Component

<script setup lang="ts">
import type { CheckboxRootEmits } from 'radix-vue'
import type { NCheckboxProps } from '../../types'
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 = computed(() => {
  const { class: _, ...delegated } = props

  return delegated
})

const forwarded = useForwardPropsEmits(delegatedProps, emits)

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

<template>
  <div
    checkbox="wrapper"
    :class="[
      una?.checkboxWrapper,
      {
        'checkbox-reverse': reverse,
      },
    ]"
  >
    <CheckboxRoot
      v-bind="forwarded"
      :id="id"
      :class="
        cn(
          'peer checkbox',
          props.class,
        )"
    >
      <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>