CheckboxNew
Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.
Import
import { Checkbox, Label } from '@heroui/react';Usage
import {Checkbox, Label} from "@heroui/react";
export function Basic() {
  return (
    <div className="flex items-center gap-3">
      <Checkbox id="terms">
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
      </Checkbox>
      <Label htmlFor="terms">Accept terms and conditions</Label>
    </div>
  );
}Anatomy
Import the Checkbox component and access all parts using dot notation.
import { Checkbox, Label, Description } from '@heroui/react';
export default () => (
  <Checkbox name="terms">
    <Checkbox.Control>
      <Checkbox.Indicator />  
    </Checkbox.Control>
    <Checkbox.Content>
      <Label />
      <Description /> {/* Optional */}
    </Checkbox.Content>
  </Checkbox>
);Disabled
This feature is coming soon
import {Checkbox, Description, Label} from "@heroui/react";
export function Disabled() {
  return (
    <div className="flex gap-3">
      <Checkbox isDisabled className="mt-0.5" id="feature">
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
      </Checkbox>
      <div className="flex flex-col gap-1">
        <Label htmlFor="feature">Premium Feature</Label>
        <Description>This feature is coming soon</Description>
      </div>
    </div>
  );
}Default Selected
import {Checkbox, Label} from "@heroui/react";
export function DefaultSelected() {
  return (
    <div className="flex items-center gap-3">
      <Checkbox defaultSelected id="notifications">
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
      </Checkbox>
      <Label htmlFor="notifications">Enable email notifications</Label>
    </div>
  );
}Controlled
Status: Enabled
"use client";
import {Checkbox, Label} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
  const [isSelected, setIsSelected] = useState(true);
  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-center gap-3">
        <Checkbox id="email-notifications" isSelected={isSelected} onChange={setIsSelected}>
          <Checkbox.Control>
            <Checkbox.Indicator />
          </Checkbox.Control>
        </Checkbox>
        <Label htmlFor="email-notifications">Email notifications</Label>
      </div>
      <p className="text-muted text-sm">
        Status: <span className="font-medium">{isSelected ? "Enabled" : "Disabled"}</span>
      </p>
    </div>
  );
}Indeterminate
Shows indeterminate state (dash icon)
"use client";
import {Checkbox, Description, Label} from "@heroui/react";
import {useState} from "react";
export function Indeterminate() {
  const [isIndeterminate, setIsIndeterminate] = useState(true);
  const [isSelected, setIsSelected] = useState(false);
  return (
    <div className="flex gap-3">
      <Checkbox
        className="mt-0.5"
        id="select-all"
        isIndeterminate={isIndeterminate}
        isSelected={isSelected}
        onChange={(selected: boolean) => {
          setIsSelected(selected);
          setIsIndeterminate(false);
        }}
      >
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
      </Checkbox>
      <div className="flex flex-col gap-1">
        <Label htmlFor="select-all">Select all</Label>
        <Description>Shows indeterminate state (dash icon)</Description>
      </div>
    </div>
  );
}With Label
import {Checkbox, Label} from "@heroui/react";
export function WithLabel() {
  return (
    <Checkbox id="marketing">
      <Checkbox.Control>
        <Checkbox.Indicator />
      </Checkbox.Control>
      <Checkbox.Content>
        <Label htmlFor="marketing">Send me marketing emails</Label>
      </Checkbox.Content>
    </Checkbox>
  );
}With Description
import {Checkbox, Description, Label} from "@heroui/react";
export function WithDescription() {
  return (
    <div className="flex gap-3">
      <Checkbox className="mt-0.5" id="notifications">
        <Checkbox.Control>
          <Checkbox.Indicator />
        </Checkbox.Control>
      </Checkbox>
      <div className="flex flex-col gap-1">
        <Label htmlFor="notifications">Email notifications</Label>
        <Description>Get notified when someone mentions you in a comment</Description>
      </div>
    </div>
  );
}Render Props
"use client";
import {Checkbox, Description, Label} from "@heroui/react";
export function RenderProps() {
  return (
    <Checkbox id="terms">
      {({isSelected}) => (
        <>
          <Checkbox.Control>
            <Checkbox.Indicator />
          </Checkbox.Control>
          <Checkbox.Content>
            <Label htmlFor="terms">{isSelected ? "Terms accepted" : "Accept terms"}</Label>
            <Description>
              {isSelected ? "Thank you for accepting" : "Please read and accept the terms"}
            </Description>
          </Checkbox.Content>
        </>
      )}
    </Checkbox>
  );
}Form Integration
"use client";
import {Button, Checkbox, Label} from "@heroui/react";
import React from "react";
export function Form() {
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);
    alert(
      `Form submitted with:\n${Array.from(formData.entries())
        .map(([key, value]) => `${key}: ${value}`)
        .join("\n")}`,
    );
  };
  return (
    <form className="flex flex-col gap-4" onSubmit={handleSubmit}>
      <div className="flex flex-col gap-3">
        <div className="flex items-center gap-3">
          <Checkbox id="notifications" name="notifications" value="on">
            <Checkbox.Control>
              <Checkbox.Indicator />
            </Checkbox.Control>
          </Checkbox>
          <Label htmlFor="notifications">Enable notifications</Label>
        </div>
        <div className="flex items-center gap-3">
          <Checkbox defaultSelected id="newsletter" name="newsletter" value="on">
            <Checkbox.Control>
              <Checkbox.Indicator />
            </Checkbox.Control>
          </Checkbox>
          <Label htmlFor="newsletter">Subscribe to newsletter</Label>
        </div>
        <div className="flex items-center gap-3">
          <Checkbox id="marketing" name="marketing" value="on">
            <Checkbox.Control>
              <Checkbox.Indicator />
            </Checkbox.Control>
          </Checkbox>
          <Label htmlFor="marketing">Receive marketing updates</Label>
        </div>
      </div>
      <Button className="mt-4" size="sm" type="submit" variant="primary">
        Submit
      </Button>
    </form>
  );
}Custom Styles
import {Checkbox, Label} from "@heroui/react";
export function CustomStyles() {
  return (
    <div className="flex items-center gap-3">
      <Checkbox id="custom">
        <Checkbox.Control className="border-2 border-purple-500 data-[selected=true]:border-purple-500 data-[selected=true]:bg-purple-500">
          <Checkbox.Indicator className="text-white" />
        </Checkbox.Control>
      </Checkbox>
      <Label htmlFor="custom">Custom styled checkbox</Label>
    </div>
  );
}Invalid
import {Checkbox, Description, Label} from "@heroui/react";
export function Invalid() {
  return (
    <Checkbox isInvalid name="agreement">
      <Checkbox.Control>
        <Checkbox.Indicator />
      </Checkbox.Control>
      <Checkbox.Content>
        <Label>I agree to the terms</Label>
        <Description>You must accept the terms to continue</Description>
      </Checkbox.Content>
    </Checkbox>
  );
}Custom Indicator
"use client";
import {Checkbox, Label} from "@heroui/react";
export function CustomIndicator() {
  return (
    <div className="flex gap-4">
      <Checkbox defaultSelected name="heart">
        <Checkbox.Control>
          <Checkbox.Indicator>
            {({isSelected}) =>
              isSelected ? (
                <svg fill="currentColor" viewBox="0 0 24 24">
                  <path
                    d="M12.62 20.81c-.34.12-.9.12-1.24 0C8.48 19.82 2 15.69 2 8.69 2 5.6 4.49 3.1 7.56 3.1c1.82 0 3.43.88 4.44 2.24a5.53 5.53 0 0 1 4.44-2.24C19.51 3.1 22 5.6 22 8.69c0 7-6.48 11.13-9.38 12.12Z"
                    fill="currentColor"
                  />
                </svg>
              ) : null
            }
          </Checkbox.Indicator>
        </Checkbox.Control>
        <Checkbox.Content>
          <Label>Heart</Label>
        </Checkbox.Content>
      </Checkbox>
      <Checkbox defaultSelected name="plus">
        <Checkbox.Control>
          <Checkbox.Indicator>
            {({isSelected}) =>
              isSelected ? (
                <svg fill="none" viewBox="0 0 24 24">
                  <path
                    d="M6 12H18"
                    stroke="currentColor"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="3"
                  />
                  <path
                    d="M12 18V6"
                    stroke="currentColor"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="3"
                  />
                </svg>
              ) : null
            }
          </Checkbox.Indicator>
        </Checkbox.Control>
        <Checkbox.Content>
          <Label>Plus</Label>
        </Checkbox.Content>
      </Checkbox>
      <Checkbox isIndeterminate name="indeterminate">
        <Checkbox.Control>
          <Checkbox.Indicator>
            {({isIndeterminate}) =>
              isIndeterminate ? (
                <svg stroke="currentColor" strokeWidth={3} viewBox="0 0 24 24">
                  <line x1="21" x2="3" y1="12" y2="12" />
                </svg>
              ) : null
            }
          </Checkbox.Indicator>
        </Checkbox.Control>
        <Checkbox.Content>
          <Label>Indeterminate</Label>
        </Checkbox.Content>
      </Checkbox>
    </div>
  );
}Full Rounded
import {Checkbox, Label} from "@heroui/react";
export function FullRounded() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex flex-col gap-3">
        <Label className="text-muted">Rounded checkboxes</Label>
        <Checkbox
          className="[&_[data-slot='checkbox-default-indicator--checkmark']]:size-2"
          name="small-rounded"
        >
          <Checkbox.Control className="size-3 rounded-full before:rounded-full">
            <Checkbox.Indicator />
          </Checkbox.Control>
          <Checkbox.Content>
            <Label>Small size</Label>
          </Checkbox.Content>
        </Checkbox>
      </div>
      <div className="flex flex-col gap-3">
        <Checkbox name="default-rounded">
          <Checkbox.Control className="size-4 rounded-full before:rounded-full">
            <Checkbox.Indicator />
          </Checkbox.Control>
          <Checkbox.Content>
            <Label>Default size</Label>
          </Checkbox.Content>
        </Checkbox>
      </div>
      <div className="flex flex-col gap-3">
        <Checkbox name="large-rounded">
          <Checkbox.Control className="size-5 rounded-full before:rounded-full">
            <Checkbox.Indicator />
          </Checkbox.Control>
          <Checkbox.Content>
            <Label>Large size</Label>
          </Checkbox.Content>
        </Checkbox>
      </div>
      <div className="flex flex-col gap-3">
        <Checkbox
          className="[&_[data-slot='checkbox-default-indicator--checkmark']]:size-4"
          name="xl-rounded"
        >
          <Checkbox.Control className="size-6 rounded-full before:rounded-full">
            <Checkbox.Indicator />
          </Checkbox.Control>
          <Checkbox.Content>
            <Label>Extra large size</Label>
          </Checkbox.Content>
        </Checkbox>
      </div>
    </div>
  );
}Styling
Passing Tailwind CSS classes
You can customize individual Checkbox components:
import { Checkbox, Label } from '@heroui/react';
function CustomCheckbox() {
  return (
    <Checkbox name="custom">
      <Checkbox.Control className="border-2 border-purple-500 data-[selected=true]:bg-purple-500">
        <Checkbox.Indicator className="text-white" />
      </Checkbox.Control>
      <Checkbox.Content>
        <Label>Custom Checkbox</Label>
      </Checkbox.Content>
    </Checkbox>
  );
}Customizing the component classes
To customize the Checkbox component classes, you can use the @layer components directive.
Learn more.
@layer components {
  .checkbox {
    @apply inline-flex gap-3 items-center;
  }
  .checkbox__control {
    @apply size-5 border-2 border-gray-400 rounded data-[selected=true]:bg-blue-500 data-[selected=true]:border-blue-500;
    /* Animated background indicator */
    &::before {
      @apply bg-accent pointer-events-none absolute inset-0 z-0 origin-center scale-50 rounded-md opacity-0 content-[''];
      
      transition:
        scale 200ms linear,
        opacity 200ms linear,
        background-color 200ms ease-out;
    }
    /* Show indicator when selected */
    &[data-selected="true"]::before {
      @apply scale-100 opacity-100;
    }
  }
  .checkbox__indicator {
    @apply text-white;
  }
  .checkbox__content {
    @apply flex flex-col gap-1;
  }
}HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The Checkbox component uses these CSS classes (View source styles):
.checkbox- Base checkbox container.checkbox__control- Checkbox control box.checkbox__indicator- Checkbox checkmark indicator.checkbox__content- Optional content container
Interactive States
The checkbox supports both CSS pseudo-classes and data attributes for flexibility:
- Selected: 
[data-selected="true"]or[aria-checked="true"](shows checkmark and background color change) - Indeterminate: 
[data-indeterminate="true"](shows indeterminate state with dash) - Invalid: 
[data-invalid="true"]or[aria-invalid="true"](shows error state with danger colors) - Hover: 
:hoveror[data-hovered="true"] - Focus: 
:focus-visibleor[data-focus-visible="true"](shows focus ring) - Disabled: 
:disabledor[aria-disabled="true"](reduced opacity, no pointer events) - Pressed: 
:activeor[data-pressed="true"] 
API Reference
Checkbox Props
Inherits from React Aria Checkbox.
| Prop | Type | Default | Description | 
|---|---|---|---|
isSelected | boolean | false | Whether the checkbox is checked | 
defaultSelected | boolean | false | Whether the checkbox is checked by default (uncontrolled) | 
isIndeterminate | boolean | false | Whether the checkbox is in an indeterminate state | 
isDisabled | boolean | false | Whether the checkbox is disabled | 
isInvalid | boolean | false | Whether the checkbox is invalid | 
isReadOnly | boolean | false | Whether the checkbox is read only | 
isOnSurface | boolean | false | Whether the checkbox is displayed on a surface (affects styling) | 
name | string | - | The name of the input element, used when submitting an HTML form | 
value | string | - | The value of the input element, used when submitting an HTML form | 
onChange | (isSelected: boolean) => void | - | Handler called when the checkbox value changes | 
children | React.ReactNode | (values: CheckboxRenderProps) => React.ReactNode | - | Checkbox content or render prop | 
CheckboxRenderProps
When using the render prop pattern, these values are provided:
| Prop | Type | Description | 
|---|---|---|
isSelected | boolean | Whether the checkbox is currently checked | 
isIndeterminate | boolean | Whether the checkbox is in an indeterminate state | 
isHovered | boolean | Whether the checkbox is hovered | 
isPressed | boolean | Whether the checkbox is currently pressed | 
isFocused | boolean | Whether the checkbox is focused | 
isFocusVisible | boolean | Whether the checkbox is keyboard focused | 
isDisabled | boolean | Whether the checkbox is disabled | 
isReadOnly | boolean | Whether the checkbox is read only |