Checkbox
A native checkbox with a hard-edged face. Fully compatible with forms.
stableCheckbox.tsx
Examples
Basic
checkbox/basic.tsx
import { Checkbox } from "@streamui/react";
export default function CheckboxBasic() {
return <Checkbox label="Remember this device" defaultChecked />;
}Group
Wrap related options in a fieldset with a legend.
checkbox/group.tsx
import { Checkbox } from "@streamui/react";
export default function CheckboxGroup() {
return (
<fieldset className="flex flex-col gap-4">
<legend className="mb-4 font-bold">Notify me about</legend>
<Checkbox name="notify" value="releases" label="New releases" defaultChecked />
<Checkbox name="notify" value="security" label="Security advisories" defaultChecked />
<Checkbox name="notify" value="digest" label="Weekly digest" />
<Checkbox name="notify" value="billing" label="Billing (required)" checked disabled readOnly />
</fieldset>
);
}Installation
bun add @streamui/reactusage.tsx
import { Checkbox } from "@streamui/react";
<Checkbox name="terms" label="I agree to the terms" />API
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | — | Visible label. The whole row is clickable. |
| checked / defaultChecked | boolean | — | Controlled or uncontrolled state, like a native input. |
| onChange | ChangeEventHandler<HTMLInputElement> | — | Native change handler. |
| className | string | — | Classes for the outer <label>. |
| ...props | Omit<ComponentProps<"input">, "type"> | — | Native input attributes such as name and value. |
Accessibility
- The real <input> stays in the DOM, visually hidden, so keyboard and assistive tech work natively.
- The visible box mirrors the input's focus ring through peer-focus-visible.
Source
packages/react/src/Checkbox.tsx
import type { ComponentProps, ReactNode } from "react";
import { Check } from "lucide-react";
import { cn } from "./cn";
export type CheckboxProps = Omit<ComponentProps<"input">, "type"> & {
label?: ReactNode;
};
/**
* A native checkbox with a brutal face. The real `<input>` stays in the DOM
* (visually hidden), so forms, keyboard, and screen readers work unchanged.
* Works controlled (`checked` + `onChange`) or uncontrolled (`defaultChecked`).
*/
export function Checkbox({ label, className, ...props }: CheckboxProps) {
return (
<label
className={cn(
"inline-flex cursor-pointer items-center gap-3 has-disabled:cursor-not-allowed has-disabled:opacity-50",
className,
)}
>
<input type="checkbox" className="peer sr-only" {...props} />
<span
aria-hidden
className={cn(
"grid size-6 shrink-0 place-items-center border-2 border-ink bg-paper-raised text-on-bright shadow-brutal-sm transition-colors duration-150",
"peer-checked:bg-lime peer-focus-visible:outline-3 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-blue",
"[&>svg]:opacity-0 peer-checked:[&>svg]:opacity-100",
)}
>
<Check className="size-4" strokeWidth={3.5} />
</span>
{label && <span className="font-semibold">{label}</span>}
</label>
);
}