Forms

Checkbox

A labeled checkbox on the Field contract, with the label to its right: pass label, and checked with onCheckedChange (or defaultChecked). Clicking the label toggles it, Space toggles it from the keyboard, the box fills and the tick draws, and indeterminate shows a dash announced as "mixed". With name, a checked box submits name=value with its form.

You can read them first.

In Spoonjoy

Spoonjoy, a recipe app, is built with Ouro HX (how).

In its source: app/components/recipe/RecipePhotoStudio.tsx · app/components/recipe/SpoonDialog.tsx · app/routes/account.settings.tsx

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/checkbox#v1.2.13

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/checkbox

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/checkbox#v1.2.13 ourostack/ouro-ui/checkbox-tests#v1.2.13
import { Checkbox } from "@/components/ouro/checkbox/checkbox";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

<Checkbox label="Email me new recipes" name="newsletter" defaultChecked />
<Checkbox label="I accept the terms" name="terms" required error={errors?.terms} />

Use instead when

  • Use CheckboxGroup instead for several choices under one legend that submit together, Switch for a setting that applies at once, and RadioGroup when only one choice may be picked.

Props

Type: CheckboxProps.

checked
Type: boolean
Whether it is checked, for a controlled checkbox; pair it with onCheckedChange.
className
Type: string
Layout only: margins, width, grid placement (mt-4, col-span-2). Appearance classes warn in development; style checkboxes in your theme.
defaultChecked
Type: boolean
Whether it starts checked, for an uncontrolled checkbox.
description
Type: ReactNode
Supporting text under the label, read after it through aria-describedby.
disabled
Type: boolean
Disables the checkbox and fades it.
error
Type: ReadonlyErrorMessages
What is wrong, from your server action or client check, shown under the label; the box gets aria-invalid. A message is text or a React node (one with a link); an empty string or array means valid. In a CheckboxGroup, pass it to the group.
hideLabel
Type: boolean
Hides the label visually; screen readers still read it as the checkbox's name.
indeterminate
Type: boolean
Shows a dash and announces "mixed": neither checked nor unchecked, as a "select all" box does when some of its items are checked. It is controlled: a click does not clear it, so clear it in onCheckedChange, as in <Checkbox indeterminate={some} checked={all} onCheckedChange={toggleAll}>. The box submits only while checked.
label (required)
Type: string
What checking it means, shown to the right of the box and read as its name. Required: every control needs a name. To hide it visually, keep it and add hideLabel.
name
Type: string
The form field name it submits under when checked. In a CheckboxGroup, the group's name applies.
onCheckedChange
Type: ((checked: boolean) => void)
Called with the new state when it is checked or unchecked.
readOnly
Type: boolean
Shows the state but ignores clicks and keys, unlike disabled, which also fades it.
ref
Type: Ref<HTMLElement>
The box element, a <span role="checkbox">.
required
Type: boolean
The box must be checked to submit the form (accepting terms): it gets required and aria-required, and the label a marker. In a CheckboxGroup, pass it to the group.
value
Type: string
What a checked box submits (on without one). In a CheckboxGroup, it identifies the box in the group's value, so it is required there.

Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

  • defaultValue: Not a prop. A checkbox's starting state is defaultChecked: <Checkbox defaultChecked>.
  • errorMessage: Not a prop. Ouro UI uses error: <Checkbox error="Required.">.
  • helperText: Not a prop. Ouro UI uses description: <Checkbox description="...">.
  • invalid: Not a prop. error marks the checkbox invalid: <Checkbox error="What is wrong">.
  • isChecked: Not a prop. Ouro UI uses checked: <Checkbox checked={agreed}>.
  • isDisabled: Not a prop. Ouro UI uses disabled: <Checkbox disabled>.
  • isIndeterminate: Not a prop. Ouro UI uses indeterminate: <Checkbox indeterminate>.
  • isInvalid: Not a prop. error marks the checkbox invalid: <Checkbox error="What is wrong">.
  • isRequired: Not a prop. Ouro UI uses required: <Checkbox required>.
  • onChange: Not a prop. Ouro UI uses onCheckedChange, which gets the new state: onCheckedChange={setChecked}.

className is for layout only

Pass margins, width and grid placement (mt-4, w-full, col-span-2).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.

Alignment classes (text-center) warn too: set alignment on a parent element.

Types

ErrorMessage

One error message: text, or a React element for a message that carries a link or other markup.

type ErrorMessage = string | ReactElement;

ReadonlyErrorMessages

A read-only message view accepted by fields and Form; mutable input arrays remain valid.

type ReadonlyErrorMessages = ErrorMessage | readonly ErrorMessage[];