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>
);
}Features and Add-ons Example
Notification preferencesChoose how you want to receive updates
Email NotificationsReceive updates via email
SMS AlertsGet instant SMS notifications
Push NotificationsBrowser and mobile push alerts
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
import {Icon} from "@iconify/react";
import clsx from "clsx";
export function FeaturesAndAddOns() {
const addOns = [
{
description: "Receive updates via email",
icon: "gravity-ui:envelope",
title: "Email Notifications",
value: "email",
},
{
description: "Get instant SMS notifications",
icon: "gravity-ui:comment",
title: "SMS Alerts",
value: "sms",
},
{
description: "Browser and mobile push alerts",
icon: "gravity-ui:bell",
title: "Push Notifications",
value: "push",
},
];
return (
<div className="flex w-full flex-col items-center gap-10 px-4 py-8">
<section className="flex w-full min-w-[320px] flex-col gap-4">
<CheckboxGroup name="notification-preferences">
<Label>Notification preferences</Label>
<Description>Choose how you want to receive updates</Description>
<div className="flex flex-col gap-2">
{addOns.map((addon) => (
<Checkbox
key={addon.value}
value={addon.value}
className={clsx(
"bg-surface-tertiary group relative flex-col gap-4 rounded-3xl px-5 py-4 transition-all",
"data-[selected=true]:bg-accent/10",
)}
>
<Checkbox.Control className="absolute right-4 top-3 size-5 rounded-full before:rounded-full">
<Checkbox.Indicator />
</Checkbox.Control>
<Checkbox.Content className="flex flex-row items-start justify-start gap-4">
<Icon className="text-accent size-5" icon={addon.icon} />
<div className="flex flex-col gap-1">
<Label>{addon.title}</Label>
<Description>{addon.description}</Description>
</div>
</Checkbox.Content>
</Checkbox>
))}
</div>
</CheckboxGroup>
</section>
</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 |