---
title: Checkbox
description: Migration guide for Checkbox from HeroUI v2 to v3
---

<Callout type="info">
  Refer to the [v3 Checkbox documentation](/docs/react/components/checkbox) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
</Callout>

## Structure Changes

In v2, `Checkbox` accepted children as the label:

```tsx
import { Checkbox } from "@heroui/react";

export default function App() {
  return <Checkbox defaultSelected>Option</Checkbox>;
}
```

In v3, Checkbox uses a compound component pattern with explicit subcomponents:

```tsx
import { Checkbox, Label } from "@heroui/react";

export default function App() {
  return (
    <Checkbox defaultSelected id="option">
      <Checkbox.Content>
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
        Option
      </Checkbox.Content>
    </Checkbox>
  );
}
```

## Key Changes

### 1. Component Structure

**v2:** Simple component with children as label  
**v3:** Compound components: `Checkbox.Content`, `Checkbox.Control`, `Checkbox.Indicator`

### 2. Label Handling

**v2:** Label passed as children directly to `Checkbox`  
**v3:** Label goes inside `Checkbox.Content` (the clickable label); `Description`/`FieldError` are siblings of `Checkbox.Content`

### 3. Prop Changes

| v2 Prop | v3 Location | Notes |
|---------|-------------|-------|
| `onValueChange` | `Checkbox` | Use `onChange` |
| `color` | - | Removed (use Tailwind on Checkbox.Control) |
| `size` | - | Removed (use Tailwind e.g. `size-4`, `size-5`) |
| `radius` | - | Removed (use Tailwind e.g. `rounded-sm`) |
| `lineThrough` | - | Removed (use Tailwind `line-through` on label) |
| `icon` | - | Use custom content in `Checkbox.Indicator` |
| `classNames` | - | Use `className` on parts |
| `disableAnimation` | - | Removed |
| — | `variant` | New prop: `"primary"` (default) or `"secondary"` for lower emphasis styling |

### 4. CheckboxGroup Changes

**v2:** `CheckboxGroup` (separate component) with `label` prop and simple `Checkbox` children  
**v3:** `CheckboxGroup` (separate component) with `Label`/`Description` as children and compound `Checkbox` structure

For migrating checkbox groups, see the [CheckboxGroup migration guide](/docs/react/migration/checkbox-group).

## Migration Examples

### Controlled Checkbox

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    import { useState } from "react";

    const [isSelected, setIsSelected] = useState(false);

    <Checkbox isSelected={isSelected} onValueChange={setIsSelected}>
      Subscribe
    </Checkbox>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    import { useState } from "react";
    import { Label } from "@heroui/react";

    const [isSelected, setIsSelected] = useState(false);

    <Checkbox id="subscribe" isSelected={isSelected} onChange={setIsSelected}>
      <Checkbox.Content>
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
        Subscribe
      </Checkbox.Content>
    </Checkbox>
    ```
  </Tab>
</Tabs>

### Checkbox with Description

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    {/* v2 doesn't have built-in description support */}
    <Checkbox defaultSelected>
      Option
    </Checkbox>
    <p className="text-sm text-default-500">Description text</p>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    import { Checkbox, Label, Description } from "@heroui/react";

    <Checkbox id="option" defaultSelected>
      <Checkbox.Content>
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
        Option
      </Checkbox.Content>
      <Description>Description text</Description>
    </Checkbox>
    ```
  </Tab>
</Tabs>

### CheckboxGroup

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    import { Checkbox, CheckboxGroup } from "@heroui/react";

    <CheckboxGroup label="Select cities">
      <Checkbox value="buenos-aires">Buenos Aires</Checkbox>
      <Checkbox value="sydney">Sydney</Checkbox>
      <Checkbox value="san-francisco">San Francisco</Checkbox>
    </CheckboxGroup>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    import { CheckboxGroup, Checkbox, Label, Description } from "@heroui/react";

    <CheckboxGroup name="cities">
      <Label>Select cities</Label>
      <Description>Choose all that apply</Description>
      <Checkbox value="buenos-aires">
        <Checkbox.Content>
          <Checkbox.Control>
            <Checkbox.Indicator />
          </Checkbox.Control>
          Buenos Aires
        </Checkbox.Content>
      </Checkbox>
      <Checkbox value="sydney">
        <Checkbox.Content>
          <Checkbox.Control>
            <Checkbox.Indicator />
          </Checkbox.Control>
          Sydney
        </Checkbox.Content>
      </Checkbox>
      <Checkbox value="san-francisco">
        <Checkbox.Content>
          <Checkbox.Control>
            <Checkbox.Indicator />
          </Checkbox.Control>
          San Francisco
        </Checkbox.Content>
      </Checkbox>
    </CheckboxGroup>
    ```
  </Tab>
</Tabs>

### Colors and Sizes

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    {/* Colors */}
    <Checkbox defaultSelected color="primary">Primary</Checkbox>
    
    {/* Sizes */}
    <Checkbox defaultSelected size="md">Medium</Checkbox>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    {/* Colors - use Tailwind classes */}
    <Checkbox defaultSelected id="primary">
      <Checkbox.Content>
        <Checkbox.Control className="data-[selected=true]:bg-primary data-[selected=true]:border-accent">
          <Checkbox.Indicator />
        </Checkbox.Control>
        Primary
      </Checkbox.Content>
    </Checkbox>
    
    {/* Sizes - use Tailwind classes */}
    <Checkbox defaultSelected id="medium">
      <Checkbox.Content>
        <Checkbox.Control className="size-5">
          <Checkbox.Indicator />
        </Checkbox.Control>
        Medium
      </Checkbox.Content>
    </Checkbox>
    ```
  </Tab>
</Tabs>

### Custom Icon/Indicator

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    <Checkbox defaultSelected icon={<HeartIcon />}>
      Option
    </Checkbox>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    <Checkbox defaultSelected id="option">
      <Checkbox.Content>
        <Checkbox.Control>
          <Checkbox.Indicator>
            {({isSelected}) => isSelected ? <HeartIcon /> : null}
          </Checkbox.Indicator>
        </Checkbox.Control>
        Option
      </Checkbox.Content>
    </Checkbox>
    ```
  </Tab>
</Tabs>

### Variants

v3 introduces a `variant` prop with `"primary"` (default) and `"secondary"` options:

```tsx
{/* Primary variant (default) */}
<Checkbox variant="primary" id="primary-option">
  <Checkbox.Content>
    <Checkbox.Control>
      <Checkbox.Indicator />
    </Checkbox.Control>
    Primary
  </Checkbox.Content>
</Checkbox>

{/* Secondary variant - lower emphasis, suitable for Surface components */}
<Checkbox variant="secondary" id="secondary-option">
  <Checkbox.Content>
    <Checkbox.Control>
      <Checkbox.Indicator />
    </Checkbox.Control>
    Secondary
  </Checkbox.Content>
</Checkbox>
```

### Indeterminate State

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    <Checkbox isIndeterminate>Option</Checkbox>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    <Checkbox isIndeterminate id="option">
      <Checkbox.Content>
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
        Option
      </Checkbox.Content>
    </Checkbox>
    ```
  </Tab>
</Tabs>

## Render Props Pattern

v3 Checkbox supports a render prop pattern that provides state information:

```tsx
<Checkbox id="terms">
  {({isSelected, isIndeterminate, isHovered, isPressed, isFocused, isDisabled}) => (
    <>
      <Checkbox.Content>
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
        
          {isSelected ? "Terms accepted" : "Accept terms"}
        
      </Checkbox.Content>
    </>
  )}
</Checkbox>
```

`Checkbox.Indicator` also supports a render prop pattern, providing the same state values. This is useful for rendering custom indicator content based on the checkbox state:

```tsx
<Checkbox id="custom">
  <Checkbox.Content>
    <Checkbox.Control>
      <Checkbox.Indicator>
        {({isSelected, isIndeterminate}) =>
          isIndeterminate ? <MinusIcon /> : isSelected ? <CheckIcon /> : null
        }
      </Checkbox.Indicator>
    </Checkbox.Control>
    Custom indicator
  </Checkbox.Content>
</Checkbox>
```

Available render props:
- `isSelected` - Whether checkbox is checked
- `isIndeterminate` - Whether checkbox is in indeterminate state
- `isHovered` - Whether checkbox is hovered
- `isPressed` - Whether checkbox is currently pressed
- `isFocused` - Whether checkbox is focused
- `isFocusVisible` - Whether checkbox should show focus indicator
- `isDisabled` - Whether checkbox is disabled
- `isReadOnly` - Whether checkbox is read only

## Styling Changes

### v2: `classNames` Prop

```tsx
<Checkbox 
  classNames={{
    base: "custom-base",
    wrapper: "custom-wrapper",
    icon: "custom-icon",
    label: "custom-label"
  }}
/>
```

### v3: Direct `className` Props

```tsx
<Checkbox className="custom-base" id="option">
  <Checkbox.Content>
    <Checkbox.Control className="custom-control">
      <Checkbox.Indicator className="custom-indicator" />
    </Checkbox.Control>
    
      Option
    
  </Checkbox.Content>
</Checkbox>
```

## Component Anatomy

The v3 Checkbox follows this structure:

```
Checkbox (Root)
  ├── Checkbox.Content (the clickable label)
  │   ├── Checkbox.Control
  │   │   └── Checkbox.Indicator
  │   └── Label
  ├── Description (optional, sibling)
  └── FieldError (optional, sibling)
```

## Summary

1. **Component Structure**: Must use compound components (`Button`, `Control`, `Indicator`)
2. **Label Handling**: Labels go inside `Checkbox.Content`
3. **onValueChange → onChange**: Event handler prop renamed
4. **Color Removed**: Use Tailwind CSS classes on `Checkbox.Control`
5. **Size Removed**: Use Tailwind CSS classes on `Checkbox.Control`
6. **Radius Removed**: Use Tailwind CSS classes on `Checkbox.Control`
7. **LineThrough Removed**: Use Tailwind `line-through` class on label
8. **Icon Prop Removed**: Use custom content in `Checkbox.Indicator`
9. **CheckboxGroup**: Same component name; use `Label`/`Description` as children and compound `Checkbox` structure
10. **ClassNames Removed**: Use `className` props on individual components
11. **New `variant` Prop**: Supports `"primary"` (default) and `"secondary"` for lower emphasis styling
12. **Indicator Render Props**: `Checkbox.Indicator` accepts a render function with state values (`isSelected`, `isIndeterminate`, etc.)
