Skip to content

Checkbox

A binary toggle for consent boxes, multi-select filters, and bulk row selection — with the neobrutalist borders-and-shadows treatment.

"use client"

import { Checkbox } from "@/components/ui/checkbox"

The checkbox is the standard control for binary choices — checked, unchecked, or indeterminate for partial selections. Built on the Base UI Checkbox primitive and styled to the neobrutalist recipe: thick borders, hard shadows, and bold type.

Reach for it when:

  • Terms and consent — the "I agree" box in signup and checkout flows, submitted with the form.
  • Multi-select filters — categories, tags, or price ranges in a sidebar where any combination is valid.
  • Bulk selection in tables — per-row checkboxes plus an indeterminate select-all in the header.

Installation

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/checkbox.json
npx shadcn@latest add https://neobrutalism.com/r/base/checkbox.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/checkbox.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/checkbox.json

Install the following dependencies:

pnpm add @base-ui/react
npm install @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react

Copy and paste the following code into your project.

components/ui/checkbox.tsx
"use client"

import * as React from "react"
import { CheckIcon } from "lucide-react"
import { Checkbox as CheckboxPrimitive } from "radix-ui"

import { cn } from "@/lib/utils"

function Checkbox({
  className,
  ...props
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
  return (
    <CheckboxPrimitive.Root
      data-slot="checkbox"
      className={cn(
        "peer relative flex size-5 shrink-0 items-center justify-center rounded border-2 bg-input shadow-sm transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive data-checked:border-border data-checked:bg-primary data-checked:text-primary-foreground",
        className
      )}
      {...props}
    >
      <CheckboxPrimitive.Indicator
        data-slot="checkbox-indicator"
        className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
      >
        <CheckIcon />
      </CheckboxPrimitive.Indicator>
    </CheckboxPrimitive.Root>
  )
}

export { Checkbox }

Update the import paths to match your project setup.

Usage

import { Checkbox } from "@/components/ui/checkbox"
<Checkbox />

Checked State

Use defaultChecked for uncontrolled checkboxes, or checked and onCheckedChange to control the state.

import * as React from "react"
 
export function Example() {
  const [checked, setChecked] = React.useState(false)
 
  return <Checkbox checked={checked} onCheckedChange={setChecked} />
}

Invalid State

Set aria-invalid on the checkbox and data-invalid on the field wrapper to show the invalid styles.

import { Checkbox } from "@/components/ui/checkbox"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"

Examples

Basic

Pair the checkbox with Field and FieldLabel for proper layout and labeling.

import { Checkbox } from "@/components/ui/checkbox"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"

Description

Use FieldContent and FieldDescription for helper text.

import { Checkbox } from "@/components/ui/checkbox"
import {
  Field,

Disabled

Use the disabled prop to prevent interaction and add the data-disabled attribute to the <Field> component for disabled styles.

import { Checkbox } from "@/components/ui/checkbox"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"

Group

Use multiple fields to create a checkbox list.

import { Checkbox } from "@/components/ui/checkbox"
import {
  Field,

Table

"use client"

import * as React from "react"

RTL

To enable RTL support in Neobrutalism.com, see the RTL configuration guide.

"use client"

import * as React from "react"

Accessibility

The checkbox follows the WAI-ARIA Checkbox pattern: the primitive renders a role="checkbox" element with aria-checked (including "mixed" for the indeterminate state) and syncs a hidden native input so the value submits with forms.

Keyboard interactions:

KeyAction
Tab / Shift + TabMove focus to or away from the checkbox
SpaceToggle the checked state (indeterminate → checked)

Enter does not toggle a checkbox — that is per the ARIA pattern, not a bug.

API Reference

See the Base UI documentation for more information.