Checkbox

Native checkbox input for a boolean form choice.

import { Checkbox } from 'ui-lab-components/checkbox';
"use client";
 
import { useState } from 'react';
import { Checkbox } from 'ui-lab-components/checkbox';
 
export default function Example() {
  const [selected, setSelected] = useState(false);
 
  return <Checkbox label="Accept terms" selected={selected} onChange={setSelected} />;
}
 

checkbox/00-permissions-panel

An invite panel — labeled permission checkboxes with helper text against a skeleton avatar stack, gating a primary action.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { Button } from 'ui-lab-components/button'
import { Checkbox } from 'ui-lab-components/checkbox'
import { Flex } from 'ui-lab-components/flex';
 
const invitees = ['Ava', 'Marcus', 'Priya'];
 
const permissions = [
  { id: 'edit', label: 'Edit files', helper: 'Create, rename, and update project files.' },
  { id: 'invite', label: 'Invite members', helper: 'Add or remove people from this workspace.' },
  { id: 'billing', label: 'Manage billing', helper: 'View invoices and change the payment method.' },
];
 
export default function Example() {
  const [granted, setGranted] = useState<Set<string>>(new Set(['edit']));
 
  const toggle = (id: string) => {
    setGranted((current) => {
      const next = new Set(current);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };
 
  return (
    <section className="flex flex-col gap-6 rounded-sm p-5">
      <Flex align-center gap="md" aria-hidden="true">
        <div className="flex -space-x-2">
          {invitees.map((_, i) => (
            <div
              key={i}
              className="h-8 w-8 rounded-full border-2 border-background-950 bg-background-700/50"
              style={{ opacity: 1 - i * 0.2 }}
            />
          ))}
        </div>
        <Flex direction="column" gap="xs">
          <div className="h-3 w-32 rounded bg-background-700/55" />
          <div className="h-2.5 w-20 rounded bg-background-700/30" />
        </Flex>
      </Flex>
 
      <div className="h-px bg-background-700/40" aria-hidden="true" />
 
      <Flex direction="column" gap="sm">
        {permissions.map((permission) => (
          <Checkbox
            key={permission.id}
            id={`permission-${permission.id}`}
            label={permission.label}
            helper={permission.helper}
            selected={granted.has(permission.id)}
            onChange={() => toggle(permission.id)}
          />
        ))}
      </Flex>
 
      <Button variant="primary" disabled={granted.size === 0} styles={{ root: 'w-full' }}>
        Send invite
      </Button>
    </section>
  );
}
 

checkbox/01-basic-states

The default checkbox states: unchecked, checked, disabled, and disabled checked.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { Checkbox } from 'ui-lab-components/checkbox'
import { Flex } from 'ui-lab-components/flex';
 
export default function Example() {
  const [selected, setSelected] = useState(true);
  return (
    <Flex direction="column" gap="md">
      <Checkbox id="basic-unchecked" label="Unchecked" />
      <Checkbox id="basic-checked" label="Checked" selected={selected} onChange={setSelected} />
      <Checkbox id="basic-disabled" label="Disabled" disabled />
      <Checkbox id="basic-disabled-checked" label="Disabled checked" disabled selected />
    </Flex>
  );
}
 

checkbox/02-helper-text

A labeled checkbox can include supporting text and an invalid state for form feedback.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { Checkbox } from 'ui-lab-components/checkbox'
import { Flex } from 'ui-lab-components/flex';
 
export default function Example() {
  const [selected, setSelected] = useState(true);
  return (
    <Flex direction="column" gap="lg">
      <Checkbox
        id="helper-release-notes"
        label="Release notes"
        helper="Get a short product update when a new version ships."
        selected={selected}
        onChange={setSelected}
      />
      <Checkbox
        id="helper-terms"
        label="Accept terms"
        helper="You must accept the terms before continuing."
        helperTextError
        aria-invalid="true"
      />
    </Flex>
  );
}
 

checkbox/03-controlled

Use selected and onChange when checkbox state is owned by the surrounding interface.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { Button } from 'ui-lab-components/button'
import { Checkbox } from 'ui-lab-components/checkbox'
import { Flex } from 'ui-lab-components/flex';
 
export default function Example() {
  const [checked, setChecked] = useState(true);
 
  return (
    <Flex direction="column" gap="md">
      <Checkbox
        id="controlled-email"
        label="Email notifications"
        helper={checked ? 'Notifications are enabled.' : 'Notifications are paused.'}
        selected={checked}
        onChange={setChecked}
      />
      <Button variant="secondary" onClick={() => setChecked((value) => !value)}>
        {checked ? 'Turn off' : 'Turn on'}
      </Button>
    </Flex>
  );
}
 

checkbox/04-group

Use a small group when a user can select any number of related options.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { Checkbox } from 'ui-lab-components/checkbox'
import { Flex } from 'ui-lab-components/flex';
 
const subscriptionOptions = [
  'Product updates',
  'Security alerts',
  'Billing reminders',
];
 
export default function Example() {
  const [selected, setSelected] = useState<Set<string>>(
    new Set(['Product updates', 'Security alerts'])
  );
 
  const toggleOption = (option: string) => {
    setSelected((current) => {
      const next = new Set(current);
      next.has(option) ? next.delete(option) : next.add(option);
      return next;
    });
  };
 
  return (
    <Flex direction="column" gap="md">
      <div>
        <p className="text-sm font-medium text-foreground-100">Subscriptions</p>
        <p className="text-xs text-foreground-400">Choose the emails this workspace receives.</p>
      </div>
      <Flex direction="column" gap="sm">
        {subscriptionOptions.map((option) => (
          <Checkbox
            key={option}
            id={`subscription-${option.toLowerCase().replace(/ /g, '-')}`}
            label={option}
            selected={selected.has(option)}
            onChange={() => toggleOption(option)}
          />
        ))}
      </Flex>
    </Flex>
  );
}
 

checkbox/05-indeterminate

A parent checkbox can show partial selection when only some child options are checked.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { Checkbox } from 'ui-lab-components/checkbox'
import { Divider } from 'ui-lab-components/divider'
import { Flex } from 'ui-lab-components/flex';
 
const tableColumns = ['Name', 'Email', 'Role', 'Last active'];
 
export default function Example() {
  const [visibleColumns, setVisibleColumns] = useState<Set<string>>(
    new Set(['Name', 'Email'])
  );
 
  const allSelected = visibleColumns.size === tableColumns.length;
  const isIndeterminate = visibleColumns.size > 0 && !allSelected;
 
  const toggleAll = () => {
    setVisibleColumns(allSelected ? new Set() : new Set(tableColumns));
  };
 
  const toggleColumn = (column: string) => {
    setVisibleColumns((current) => {
      const next = new Set(current);
      next.has(column) ? next.delete(column) : next.add(column);
      return next;
    });
  };
 
  return (
    <Flex direction="column" gap="sm">
      <Checkbox
        id="columns-all"
        label="Show all columns"
        selected={allSelected} indeterminate={isIndeterminate}
        onChange={toggleAll}
      />
      <Divider />
      <Flex direction="column" gap="sm" className="pl-8">
        {tableColumns.map((column) => (
          <Checkbox
            key={column}
            id={`column-${column.toLowerCase().replace(/ /g, '-')}`}
            label={column}
            selected={visibleColumns.has(column)}
            onChange={() => toggleColumn(column)}
          />
        ))}
      </Flex>
    </Flex>
  );
}