Checkbox
Customizable checkbox with support for indeterminate state
Checkbox
A checkbox component with custom styling and support for the indeterminate state, useful for "select all" scenarios where only some items are selected.
Installation
import { Checkbox } from '@geckoui/geckoui';Basic Usage
import { useState } from 'react';
function Example() {
const [checked, setChecked] = useState(false);
return (
<Checkbox
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
);
}Props API
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | - | Controlled checked state |
indeterminate | boolean | false | Show the mixed state. Independent of checked, like the native DOM property |
disabled | boolean | false | Disable the checkbox |
aria-invalid | boolean | - | Marks the box invalid, to a screen reader and in its colours |
className | string | - | CSS class for the checkbox box |
onChange | ChangeEventHandler | - | Callback when checked state changes |
| ...rest | InputHTMLAttributes | - | All standard HTML input attributes |
Examples
With Label
import { useState } from 'react';
function CheckboxWithLabel() {
const [agreed, setAgreed] = useState(false);
return (
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
/>
<span>I agree to the terms and conditions</span>
</label>
);
}Indeterminate State
import { useState } from 'react';
function SelectAll() {
const [items, setItems] = useState([
{ id: 1, checked: false },
{ id: 2, checked: false },
{ id: 3, checked: false },
]);
const allChecked = items.every(item => item.checked);
const someChecked = items.some(item => item.checked);
const handleSelectAll = (e: React.ChangeEvent<HTMLInputElement>) => {
setItems(items.map(item => ({ ...item, checked: e.target.checked })));
};
return (
<div>
<label className="flex items-center gap-2">
<Checkbox
checked={allChecked}
indeterminate={someChecked && !allChecked}
onChange={handleSelectAll}
/>
<span>Select All</span>
</label>
{/* Individual items... */}
</div>
);
}How indeterminate behaves
indeterminate mirrors the native DOM property. It is purely visual and independent of
checked, so a "select all" box shows the dash while staying unchecked:
checked | indeterminate | Shows |
|---|---|---|
false | false | empty box |
false | true | dash |
true | false | tick |
true | true | dash |
Because it is a DOM property with no matching HTML attribute, the component writes it to
the input directly. That is what makes the :indeterminate CSS pseudo-class match and lets
assistive tech report the mixed state.
Disabled States
<div className="space-y-2">
<Checkbox checked disabled />
<Checkbox disabled />
</div>Multiple Checkboxes
function NotificationSettings() {
const [settings, setSettings] = useState({
email: true,
sms: false,
push: true,
});
return (
<div className="space-y-3">
<label className="flex items-center gap-2">
<Checkbox
checked={settings.email}
onChange={(e) => setSettings({...settings, email: e.target.checked})}
/>
<span>Email notifications</span>
</label>
{/* Other checkboxes... */}
</div>
);
}Keyboard Navigation
The checkbox supports full keyboard navigation:
- Space or Enter: Toggle checkbox
- Tab: Move focus to next element
- Shift + Tab: Move focus to previous element
Accessibility
- Renders a native
<input type="checkbox">, so role and checked state are implicit - The
indeterminateDOM property is set on the input, so the mixed state is announced - Keyboard accessible with Space and Enter keys
- Focus management for keyboard users
- Works with screen readers
- Disabled state properly communicated
Styling
GeckoUICheckbox- Main containerGeckoUICheckbox__input- Native checkbox input, styled as the visual boxGeckoUICheckbox__icon- Check or indeterminate icon
Icons
- CheckIcon: Displayed when
checked={true}andindeterminate={false} - IndeterminateIcon: Displayed when
indeterminate={true}
Related Components
- Radio - For mutually exclusive selections
- Switch - Toggle alternative
- RHFCheckbox - React Hook Form integration