Frappe UIFrappe UI

Checkbox

Allows users to select or deselect an option, commonly used in forms and settings where multiple choices are available.

Playground

label
description
size
padded
indeterminate
required
error
disabled
<Checkbox
  label="I agree"
  v-model="value"
/>

Indeterminate

Use indeterminate for "select all" controls where only some children are checked. Clicking selects all; clicking again deselects all.

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>

States

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

<template>
  <div class="flex flex-col gap-3 items-start">
    <Checkbox label="Default" />
    <Checkbox label="Required" required />
    <Checkbox label="Disabled" disabled />
    <Checkbox label="With error" error="Required to continue." />
  </div>
</template>

Selection list

For a full selection dropdown, reach for MultiSelect — it builds the popover, search, and checkbox rows for you. Add avatars or icons to each option with its #item-prefix slot.

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

const selected = ref<string[]>([])

const members = [
  { value: 'aaron-menezes', label: 'Aaron Menezes' },
  { value: 'vaani-kapoor', label: 'Vaani Kapoor' },
  { value: 'daniel-kapoor', label: 'Daniel Kapoor' },
  { value: 'steven-james', label: 'Steven James' },
  { value: 'dipen-gala', label: 'Dipen Gala' },
]
</script>

<template>
  <MultiSelect
    v-model="selected"
    :options="members"
    placeholder="Select members"
    class="w-64"
  >
    <template #item-prefix="{ item }">
      <Avatar :label="item.label" size="sm" />
    </template>
  </MultiSelect>
</template>

Settings list

Without padded, a description stacks below the label, indented under the control. Useful for settings where some options need extra explanation.

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>

With description

Pair each option with helper text to clarify its effect.

If enabled, the value specified or calculated in this component will not contribute to the earnings or deductions. However, its value can be referenced by other components that can be added or deducted.

If enabled, the value specified or calculated in this component will not contribute to the earnings or deductions. However, its value can be referenced by other components that can be added or deducted.

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

const settings = reactive({
  roundToInteger: false,
  removeIfZero: false,
})

const helperText =
  'If enabled, the value specified or calculated in this component will not contribute to the earnings or deductions. However, its value can be referenced by other components that can be added or deducted.'
</script>

<template>
  <div class="flex flex-col gap-3 items-start w-[28rem]">
    <Checkbox
      v-model="settings.roundToInteger"
      label="Round to the nearest integer"
      :description="helperText"
    />
    <Checkbox
      v-model="settings.removeIfZero"
      label="Remove if zero valued"
      :description="helperText"
    />
  </div>
</template>

Horizontal group

Wrap multiple options inline 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 row

Compose a checkbox group as the value side of a label/value row.

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>

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
string | FrappeUIError

Error message rendered below the input. When set, the control receives `aria-invalid="true"` and `data-state="invalid"`. May be either a string or an `Error` object whose `messages?: string[]` is rendered as stacked lines (with `Error.message` as the fallback).

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.