Checkbox
A control that allows the user to toggle between checked and not checked.
npx shadcn@latest add @velaui/checkboxpnpm dlx velaui add @velaui/checkboxyarn dlx shadcn@latest add @velaui/checkboxbunx --bun shadcn@latest add @velaui/checkboxveni add checkboxInstalls the copy of vela-ui that veni-builder serves to Venizia apps; veni-builder serves the Radix UI copy only, so this tab exists for that base alone.
npx shadcn@latest add @velaui/checkboxpnpm dlx velaui add @velaui/checkboxyarn dlx shadcn@latest add @velaui/checkboxbunx --bun shadcn@latest add @velaui/checkboxExamples
- Default
- Basic
- With description
- Disabled
- Error
- Group
Usage
Props
Checkbox
| Prop | Type | Default |
|---|---|---|
size | "sm" | "md" | "lg" | "md" |
Takes these and every prop of CheckboxProps.
CheckboxField
Takes every prop of CheckboxFieldProps.
CheckboxLabel
Takes every prop of CheckboxLabelProps.
CheckboxDescription
Takes every prop of CheckboxDescriptionProps.
Dependencies
- npm
class-variance-authority@0.7.1radix-ui@1.6.0- Installs with it
- 1 icon
- npm
@base-ui/react@1.6.0class-variance-authority@0.7.1- Installs with it
- 1 icon
Source
components/ui/checkbox.tsx
/* eslint-disable react-refresh/only-export-components */
import * as React from "react";
import {
Checkbox as CheckboxPrimitive,
Label as LabelPrimitive,
} from "radix-ui";
import { cva, type VariantProps } from "class-variance-authority";
import { Check01 } from "@/components/icons/check-01";
import { cn } from "@/lib/utils";
const checkboxVariants = cva(
[
"peer relative flex shrink-0 items-center justify-center border-[1.5px] border-border-default text-icon-inverse transition-colors outline-none after:absolute after:-inset-x-3 after:-inset-y-2",
// Hover
"hover:border-border-hover hover:bg-bg-surface-1",
// Focus — the design draws it as an outside stroke, so it must be a ring
// (a border would eat into the box and shift the indicator).
"focus-visible:ring-2 focus-visible:ring-border-default focus-visible:border-ring-neutral-outline",
// Checked — the fill replaces the stroke; a transparent border of the same
// width keeps the box model identical across states.
"data-checked:border-transparent data-checked:bg-bg-foreground data-checked:hover:border-transparent data-checked:hover:bg-primary-hover",
// Disabled
"disabled:cursor-not-allowed disabled:border-border-disabled disabled:bg-input-default disabled:text-icon-disabled disabled:hover:border-border-disabled disabled:hover:bg-input-default disabled:data-checked:border-transparent disabled:data-checked:bg-bg-disabled",
// Alert
"aria-invalid:border-negative-middle aria-invalid:hover:border-negative-middle aria-invalid:data-checked:border-transparent aria-invalid:data-checked:bg-negative-middle aria-invalid:data-checked:hover:bg-negative-middle",
// Alert focus
"aria-invalid:focus-visible:bg-bg-main aria-invalid:focus-visible:ring-2 aria-invalid:focus-visible:ring-negative-middle/25 aria-invalid:data-checked:focus-visible:bg-negative-middle",
],
{
variants: {
size: {
sm: "size-4 rounded-sm [&_svg]:size-2.5",
md: "size-[18px] rounded-[5px] [&_svg]:size-2.75",
lg: "size-[22px] rounded-md [&_svg]:size-3.25",
},
},
defaultVariants: {
size: "md",
},
},
);
export type CheckboxProps = React.ComponentProps<typeof CheckboxPrimitive.Root> &
VariantProps<typeof checkboxVariants>;
function Checkbox({
className,
size = "md",
...props
}: CheckboxProps) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
data-size={size}
className={cn(checkboxVariants({ size }), className)}
{...props}
>
<CheckboxPrimitive.Indicator
data-slot="checkbox-indicator"
className="grid place-content-center text-current transition-none"
>
<Check01 />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
);
}
export type CheckboxFieldProps = React.ComponentProps<"div">;
function CheckboxField({ className, ...props }: CheckboxFieldProps) {
return (
<div
data-slot="checkbox-field"
className={cn(
"group/checkbox-field flex flex-col items-start justify-center gap-2",
className,
)}
{...props}
/>
);
}
export type CheckboxLabelProps = React.ComponentProps<typeof LabelPrimitive.Root>;
function CheckboxLabel({
className,
...props
}: CheckboxLabelProps) {
return (
<LabelPrimitive.Root
data-slot="checkbox-label"
className={cn(
"flex items-center gap-2 text-sm leading-[1.4] font-normal text-text-muted select-none has-disabled:cursor-not-allowed has-disabled:text-text-note",
className,
)}
{...props}
/>
);
}
export type CheckboxDescriptionProps = React.ComponentProps<"p">;
function CheckboxDescription({
className,
...props
}: CheckboxDescriptionProps) {
return (
<p
data-slot="checkbox-description"
className={cn(
"text-xs leading-[1.3] text-text-note group-has-aria-invalid/checkbox-field:text-negative-middle",
className,
)}
{...props}
/>
);
}
export {
Checkbox,
CheckboxField,
CheckboxLabel,
CheckboxDescription,
checkboxVariants,
};components/ui/checkbox.tsx
/* eslint-disable react-refresh/only-export-components */
import * as React from "react";
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
import { cva, type VariantProps } from "class-variance-authority";
import { Check01 } from "@/components/icons/check-01";
import { cn } from "@/lib/utils";
const checkboxVariants = cva(
[
"peer relative flex shrink-0 items-center justify-center border-[1.5px] border-border-default text-icon-inverse transition-colors outline-none after:absolute after:-inset-x-3 after:-inset-y-2",
// Hover
"hover:border-border-hover hover:bg-bg-surface-1",
// Focus — the design draws it as an outside stroke, so it must be a ring
// (a border would eat into the box and shift the indicator).
"focus-visible:ring-2 focus-visible:ring-border-default focus-visible:border-ring-neutral-outline",
// Checked — the fill replaces the stroke; a transparent border of the same
// width keeps the box model identical across states.
"data-checked:border-transparent data-checked:bg-bg-foreground data-checked:hover:border-transparent data-checked:hover:bg-primary-hover",
// Disabled — Base UI renders a span (not a button), so disabled styling
// keys off its data-disabled attribute instead of :disabled.
"data-disabled:cursor-not-allowed data-disabled:border-border-disabled data-disabled:bg-input-default data-disabled:text-icon-disabled data-disabled:hover:border-border-disabled data-disabled:hover:bg-input-default data-disabled:data-checked:border-transparent data-disabled:data-checked:bg-bg-disabled",
// Alert
"aria-invalid:border-negative-middle aria-invalid:hover:border-negative-middle aria-invalid:data-checked:border-transparent aria-invalid:data-checked:bg-negative-middle aria-invalid:data-checked:hover:bg-negative-middle",
// Alert focus
"aria-invalid:focus-visible:bg-bg-main aria-invalid:focus-visible:ring-2 aria-invalid:focus-visible:ring-negative-middle/25 aria-invalid:data-checked:focus-visible:bg-negative-middle",
],
{
variants: {
size: {
sm: "size-4 rounded-sm [&_svg]:size-2.5",
md: "size-[18px] rounded-[5px] [&_svg]:size-2.75",
lg: "size-[22px] rounded-md [&_svg]:size-3.25",
},
},
defaultVariants: {
size: "md",
},
},
);
export type CheckboxProps = CheckboxPrimitive.Root.Props & VariantProps<typeof checkboxVariants>;
function Checkbox({
className,
size = "md",
...props
}: CheckboxProps) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
data-size={size}
className={cn(checkboxVariants({ size }), className)}
{...props}
>
<CheckboxPrimitive.Indicator
data-slot="checkbox-indicator"
className="grid place-content-center text-current transition-none"
>
<Check01 />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
);
}
export type CheckboxFieldProps = React.ComponentProps<"div">;
function CheckboxField({ className, ...props }: CheckboxFieldProps) {
return (
<div
data-slot="checkbox-field"
className={cn(
"group/checkbox-field flex flex-col items-start justify-center gap-2",
className,
)}
{...props}
/>
);
}
export type CheckboxLabelProps = React.ComponentProps<"label">;
function CheckboxLabel({
className,
...props
}: CheckboxLabelProps) {
return (
<label
data-slot="checkbox-label"
className={cn(
"flex items-center gap-2 text-sm leading-[1.4] font-normal text-text-muted select-none has-disabled:cursor-not-allowed has-disabled:text-text-note",
className,
)}
{...props}
/>
);
}
export type CheckboxDescriptionProps = React.ComponentProps<"p">;
function CheckboxDescription({
className,
...props
}: CheckboxDescriptionProps) {
return (
<p
data-slot="checkbox-description"
className={cn(
"text-xs leading-[1.3] text-text-note group-has-aria-invalid/checkbox-field:text-negative-middle",
className,
)}
{...props}
/>
);
}
export {
Checkbox,
CheckboxField,
CheckboxLabel,
CheckboxDescription,
checkboxVariants,
};