Skip to content
v2.5.0
English
Русский
Documentation

Checkbox

Checkbox is a compound component for independent selectable options, with optional native form participation, indicator rendering, and indeterminate state support.
checkbox.tsx · 27 lines
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Text,
} from '@vega-ui/react';

<div>
  <Checkbox style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
    <CheckboxInput defaultChecked />
Browser support
Widely available
  • Chrome 111
  • Edge 111
  • Firefox 121
  • Safari 15.4
  • Safari on iOS 15.4
Bundle size
Tested in
26 tests

Summary

Checkbox is a compound component for independent selectable options, with optional native form participation, indicator rendering, and indeterminate state support. It is the selection-family primitive for independent or combinable choices rather than immediate setting toggles.

Imports

import {
  Checkbox,
  CheckboxInput,
  CheckboxIndicator,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  type CheckboxProps,
  type CheckboxSize,
  type CheckboxVariant,
} from '@vega-ui/react';

Exported Types

  • CheckboxProps
  • CheckboxInputProps
  • CheckboxIndicatorProps
  • CheckboxCheckedIconProps
  • CheckboxIndeterminateIconProps
  • CheckboxSize
  • CheckboxVariant

Minimal Composition

minimal-composition.tsx · 20 lines
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
} from '@vega-ui/react';

export default function MinimalComposition() {
  return (
    <Checkbox style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-4)' }}>
      <CheckboxInput name='remember' />

Required Parts

  • Checkbox: root state and label surface
  • CheckboxInput: the native checkbox — focus, keyboard, state and form value
  • CheckboxIndicator: visible checkbox surface

Optional Parts

  • CheckboxCheckedIcon: checked-state icon
  • CheckboxIndeterminateIcon: indeterminate-state icon

Composition Order

  1. Checkbox
  2. CheckboxInput
  3. CheckboxIndicator
  4. CheckboxCheckedIcon
  5. CheckboxIndeterminateIcon
  6. label text

Variants

  • Sizes: sm, md, lg
  • Variants: primary, secondary
  • States: unchecked, checked, indeterminate, disabled

Edge Cases

  • Give CheckboxInput a name for native form submission.
  • Indeterminate usually represents partial selection rather than a third final value.
  • Keep indicator and text inside one unified clickable row.
  • If the control represents one immediate system setting, Switch is usually clearer than a checkbox row.

Common Mistakes

  • Leaving out CheckboxInput, which is the actual control.
  • Treating indeterminate as a final persisted state by default.
  • Using checkbox UI for mutually exclusive options.

Examples

Basic

Basic: group of independent options

A Fieldset with a legend groups several independent choices. Each Checkbox is the <label> itself, so the text inside it is the accessible name and the whole row is clickable. Every input shares one name and carries its own value.

labeled-checkbox.tsx · 35 lines
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Fieldset,
  FieldsetLegend,
} from '@vega-ui/react';

const options = [
  { value: 'mentions', label: 'Someone mentions me in a comment', checked: true },

Controlled/Stateful

Controlled/Stateful: parent with indeterminate state

The parent checkbox is derived from the children: checked when all permissions are granted, indeterminate when only some are. Clicking it selects or clears the whole group, and the counter below reads the same state.

indeterminate-parent-selector.tsx · 62 lines
import { useState } from 'react';
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Text,
} from '@vega-ui/react';

const permissions = ['View invoices', 'Download invoices', 'Edit payment methods', 'Cancel subscription'];

Form/Integration

Form/Integration: reading values with FormData

Checked inputs with the same name submit as repeated entries, so FormData.getAll('topics') returns every selected value. A single checkbox submits its value only when checked; an unchecked one is absent from the form data. The reset button restores defaultChecked.

form-data-submission.tsx · 68 lines
import { FormEvent, useState } from 'react';
import {
  Button,
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Fieldset,
  FieldsetLegend,
  Text,
} from '@vega-ui/react';

Layout/Overlay

Layout/Overlay: filter list inside a drawer

The checkboxes live in a form method='dialog' inside a Drawer: submitting reads FormData, applies the filters and closes the drawer. The trigger shows how many filters are applied, and reopening the drawer starts from the applied values.

checkbox-list-inside-a-drawer.tsx · 76 lines
import { CSSProperties, FormEvent, useState } from 'react';
import {
  Button,
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerTrigger,

Layout/Overlay: row selection in a table

Checkboxes in table cells have no visible text, so each CheckboxInput gets an aria-label naming its row. The header checkbox selects all rows and turns indeterminate on partial selection; the toolbar action reacts to the selection.

table-row-selection.tsx · 91 lines
import { useState } from 'react';
import {
  Button,
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Table,
  TableBody,
  TableData,
  TableHead,

Error

Error: required agreement

The input is natively required. Its invalid event replaces the browser bubble with a HelperText linked through aria-describedby and sets aria-invalid; checking the box clears the error.

required-agreement-checkbox.tsx · 59 lines
import { FormEvent, useState } from 'react';
import {
  Button,
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  HelperText,
} from '@vega-ui/react';

export default function RequiredAgreementCheckbox() {

Disabled

Disabled: disabled by a fieldset

While “Use workspace defaults” is checked, the Fieldset is disabled and every checkbox inside inherits it natively. The security alerts option is always disabled and explains why through aria-describedby. Disabled inputs are not submitted with the form.

disabled-by-fieldset.tsx · 60 lines
import { useState } from 'react';
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Fieldset,
  FieldsetLegend,
  HelperText,
} from '@vega-ui/react';

Edge

Edge: long labels in a narrow column

Long text wraps under itself while the indicator stays at the first line: align the row to flex-start and give CheckboxIndicator flex-shrink: 0, otherwise flex squeezes the box. Unbroken strings such as email addresses need overflow-wrap: anywhere.

long-label-wrapping.tsx · 32 lines
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
} from '@vega-ui/react';

export default function LongLabelWrapping() {
  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-8)', width: '100%' }}>
      <Checkbox style={{ display: 'flex', alignItems: 'flex-start', gap: 'var(--spacing-4)' }}>

Edge: hundreds of options with select all

240 options in a scrollable group, with a Set of selected values so toggling stays cheap. The select-all checkbox derives checked and indeterminate from the set size.

many-options-with-select-all.tsx · 80 lines
import { useState } from 'react';
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
  Text,
} from '@vega-ui/react';

const teams = ['billing', 'search', 'auth', 'checkout', 'payments', 'catalog', 'inventory', 'shipping', 'reviews', 'ads', 'email', 'reports'];
const services = ['api', 'worker', 'web', 'gateway', 'scheduler'];

Anatomy

Overview

Checkbox is a compound component that coordinates checked, indeterminate, disabled, and form-participation behavior across a root label and exported visual parts.

Required Parts

Checkbox

Required. Owns size, variant, checked, indeterminate, and disabled state.

CheckboxIndicator

Required for the visible control surface.

CheckboxInput

Required. The visually hidden native checkbox: focus, keyboard, checked state and form value come from it. Without it the indicator is an empty, unfocusable box.

Optional Parts

CheckboxCheckedIcon

Optional checked-state icon inside the indicator.

CheckboxIndeterminateIcon

Optional indeterminate-state icon inside the indicator.

Composition Order

  1. Checkbox
  2. CheckboxInput
  3. CheckboxIndicator
  4. CheckboxCheckedIcon
  5. CheckboxIndeterminateIcon
  6. label text

Valid Composition Patterns

Two valid shapes: text inside the Checkbox root, which is the <label> and gives the input its name, and a bare checkbox (for example in a table cell) whose CheckboxInput gets an aria-label. CheckboxIndeterminateIcon can be left out when the checkbox never becomes indeterminate.

valid-composition-patterns.tsx · 28 lines
import {
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndeterminateIcon,
  CheckboxIndicator,
  CheckboxInput,
} from '@vega-ui/react';

export default function ValidCompositionPatterns() {
  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-8)' }}>
      <Checkbox style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-4)' }}>

Invalid Composition Patterns

Visual indicator without CheckboxInput

This leaves no focusable control and breaks native form participation.

Indeterminate used as a final persisted state by accident

Indeterminate is usually a visual partial-selection state, not a separate business value.

Split label and indicator as separate click targets

The root label should keep the control and text together as one interaction row.