Checkbox ​

A box that turns one option on or off. For a dropdown that picks several options, use MultiSelect, which draws the checkbox rows for you.

label
description
size
<Checkbox
  label="I agree"
  v-model="value"
/>

Examples ​

Select all ​

A parent checkbox with indeterminate shows that only some of its children are checked. Clicking it checks all of them, and clicking again clears them. padded gives each row a clickable surface.

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

const items = ref([
  { label: 'Notifications', checked: true },
  { label: 'Weekly digest', checked: false },
  { label: 'Marketing emails', checked: true },
])

const allChecked = ref(false)

const indeterminate = ref(
  items.value.some((i) => i.checked) && !items.value.every((i) => i.checked),
)

function onSelectAll(val: boolean | 0 | 1 | undefined) {
  const checked = Boolean(val)
  items.value.forEach((i) => (i.checked = checked))
  allChecked.value = checked
  indeterminate.value = false
}

function onItemChange() {
  const checkedCount = items.value.filter((i) => i.checked).length
  allChecked.value = checkedCount === items.value.length
  indeterminate.value = checkedCount > 0 && checkedCount < items.value.length
}
</script>

<template>
  <div class="flex flex-col gap-1 w-48">
    <Checkbox
      :indeterminate="indeterminate"
      :model-value="allChecked"
      label="Select all"
      padded
      @update:model-value="onSelectAll"
    />
    <div class="pl-4 flex flex-col gap-1">
      <Checkbox
        v-for="item in items"
        :key="item.label"
        v-model="item.checked"
        :label="item.label"
        padded
        @update:model-value="onItemChange"
      />
    </div>
  </div>
</template>

Notification settings ​

A description shows below the label, lined up with the label text.

Get notified when an email is received on any of the documents assigned to you.

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

const settings = ref({
  email: true,
  mentions: true,
  threads: true,
  events: false,
})
</script>

<template>
  <div class="flex w-96 flex-col gap-4">
    <Checkbox v-model="settings.email" label="Enable email notifications" />
    <Checkbox v-model="settings.mentions" label="Mentions" />
    <Checkbox
      v-model="settings.threads"
      label="Email threads on assigned document"
      description="Get notified when an email is received on any of the documents assigned to you."
    />
    <Checkbox v-model="settings.events" label="Event reminders" />
  </div>
</template>

Checkboxes in a row that wraps, under a section title.

Print settings

vue
<script setup lang="ts">
import { reactive } from 'vue'
import { Checkbox } from 'frappe-ui'

const settings = reactive({
  inclusiveText: false,
  paymentSchedule: false,
  taxesAsTable: true,
})
</script>

<template>
  <div class="flex flex-col gap-4 items-start w-[32rem]">
    <p class="text-lg-medium text-ink-gray-9">Print settings</p>
    <div class="flex flex-wrap gap-x-8 gap-y-2">
      <Checkbox v-model="settings.inclusiveText" label="Show inclusive text in print" />
      <Checkbox
        v-model="settings.paymentSchedule"
        label="Show payment schedule in print"
      />
      <Checkbox v-model="settings.taxesAsTable" label="Show taxes as table in print" />
    </div>
  </div>
</template>

Setting with several values ​

A column of checkboxes as the value side of a label and value row. One option is disabled, so it always stays checked.

Default ticket type

vue
<script setup lang="ts">
import { reactive } from 'vue'
import { Checkbox } from 'frappe-ui'

const ticketTypes = reactive({
  primary: true,
  promotions: true,
  social: true,
  updates: true,
})
</script>

<template>
  <div class="flex gap-3 items-start border-b border-outline-gray-1 py-3 w-[28rem]">
    <p class="text-base text-ink-gray-7 pt-1.5 w-40 shrink-0">Default ticket type</p>
    <div class="flex flex-col gap-1 items-start">
      <Checkbox v-model="ticketTypes.primary" label="Primary" disabled />
      <Checkbox v-model="ticketTypes.promotions" label="Promotions" />
      <Checkbox v-model="ticketTypes.social" label="Social" />
      <Checkbox v-model="ticketTypes.updates" label="Updates" />
    </div>
  </div>
</template>

Behavior ​

Value ​

The value is a boolean. 1 and 0 also work, and stay supported in v1.

Indeterminate ​

indeterminate draws the mixed state. It only changes how the box looks, and you must set it with the prop: the browser does not read an indeterminate attribute from markup.

Padded ​

padded wraps the box and the label in a clickable surface with hover, active and focus states, for selection lists and menu items. The box stays on the leading side.

Label, description and error ​

label renders beside the box and description below it, lined up with the label text. error renders below the label and hides description. It takes a string, an array of strings (one line each), or an Error, the same values as ErrorMessage. An empty string or an empty array means no error. required adds a red asterisk to the label and sets required on the <input>.

The #label slot replaces the label text and the required marker, and receives { required }. A #description slot is not hidden by error. It renders above the error.

Attributes ​

class and style go on the outer element, which holds the box, the label, the description and the error. Every other attribute and listener goes on the <input type="checkbox">, including name, aria-* and @change.

Accessibility ​

Checkbox renders a native <input type="checkbox">, so Space toggles it. required sets aria-required. While error is set, the input gets aria-invalid and an aria-errormessage that points to the error text.

API Reference ​

Show types
typescript
import type { ToggleSize } from '../../composables/inputTypes'
import type { InputLabelingProps } from '../../composables/useInputLabeling'

export interface CheckboxBaseProps extends InputLabelingProps {
  /** Controls the size of the checkbox */
  size?: ToggleSize

  /** Wraps the control and label in a clickable surface with hover, active and focus states — useful for selection lists and menu items. The control always stays on the leading side. */
  padded?: boolean

  /** Disables the checkbox interaction */
  disabled?: boolean

  /**
   * Renders the mixed "—" state (e.g. a select-all that's partially selected).
   * Purely visual — the native `indeterminate` DOM property is not reflected as
   * an attribute, so it must be set via this prop, not markup.
   */
  indeterminate?: boolean
}

/** Public prop shape; the component itself declares this model through `defineModel`. */
export type CheckboxProps = CheckboxBaseProps & {
  /** Checked state. `boolean` is canonical; `1`/`0` remain supported throughout v1. */
  modelValue?: boolean | 1 | 0
}
size
= "sm"
ToggleSize

Controls the size of the checkbox

padded
= false
boolean

Wraps the control and label in a clickable surface with hover, active and focus states — useful for selection lists and menu items. The control always stays on the leading side.

disabled
boolean

Disables the checkbox interaction

indeterminate
= false
boolean

Renders the mixed "—" state (e.g. a select-all that's partially selected). Purely visual — the native `indeterminate` DOM property is not reflected as an attribute, so it must be set via this prop, not markup.

label
string

Label rendered above (or beside, for binary controls) the input.

description
string

Helper text rendered below the input. Hidden when `error` is set. A `#description` slot is not: it renders beside the error, and is referenced alongside it.

error
ErrorMessageValue

Error message rendered below the input. When set, the control receives `aria-invalid="true"` and `data-state="invalid"`. Takes a string, an array of strings, or an `Error` whose `messages` are rendered as stacked lines (with `Error.message` as the fallback). This is the same value `ErrorMessage.message` takes. An empty array and an empty string both mean no error.

required
boolean

Marks the field as required. Renders an asterisk next to the label, with `sr-only` text that announces it, and forwards `required` / `aria-required` to the underlying control where the control's role allows it. `data-required` is set either way.

id
string

HTML id of the underlying control. Auto-generated via `useId()` if omitted.

modelValue
boolean | 0 | 1
label
{ required: boolean; }

Overrides the rendered label content. Receives `{ required }`.

description
—

Overrides the rendered description content.

update:modelValue
[value: boolean | 0 | 1 | undefined]

Fired when the model value changes.

focus
(options?: FocusOptions) => void

Moves focus to the checkbox.