Checkbox
Allows users to select or deselect an option, commonly used in forms and settings where multiple choices are available.
Playground
<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.
<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
<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.
<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.
<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.
<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.
<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.
<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
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
}Controls the size of the checkbox
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.
Disables the checkbox interaction
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 rendered above (or beside, for binary controls) the input.
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 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).
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.
HTML id of the underlying control. Auto-generated via `useId()` if omitted.
| Slot | Payload |
|---|---|
label | { required: boolean; } Overrides the rendered label content. Receives `{ required }`. |
description | — Overrides the rendered description content. |
Overrides the rendered label content. Receives `{ required }`.
Overrides the rendered description content.
| Event | Payload |
|---|---|
update:modelValue | [value: boolean | 0 | 1 | undefined] Fired when the model value changes. |
Fired when the model value changes.