Rendered by React 19.3.1
Loading React…import * as React from 'react'
import { Checkbox } from '@hamur/react/checkbox'
import { CheckboxGroup } from '@hamur/react/checkbox-group'
const fruits = ['apple', 'banana', 'cherry']
export default function CheckboxGroupExample() {
const [value, setValue] = React.useState<string[]>(['banana'])
return (
<div className="stack">
<CheckboxGroup
className="stack"
allValues={fruits}
value={value}
onValueChange={setValue}
>
<label className="row">
<Checkbox.Root className="checkbox" parent>
<Checkbox.Indicator className="checkbox-indicator"><span className="checkbox-check">✓</span><span className="checkbox-dash">–</span></Checkbox.Indicator>
</Checkbox.Root>
All fruit
</label>
{fruits.map((fruit) => (
<label className="row nested" key={fruit}>
<Checkbox.Root className="checkbox" value={fruit}>
<Checkbox.Indicator className="checkbox-indicator">✓</Checkbox.Indicator>
</Checkbox.Root>
{fruit}
</label>
))}
</CheckboxGroup>
<p className="muted">Selected: {value.join(', ') || 'none'}</p>
</div>
)
}
199Tests passing in React · 0 failing
5.0 KiBSize
Not measured yetMemory
Not measured yetSpeed
Installation
npm i @hamur/react
Not on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
Examples
Parent
allValues and a parent checkbox check or clear every child; the parent is mixed in between.
CheckboxGroupParent.tsx
import * as React from 'react'
import { Checkbox } from '@hamur/react/checkbox'
import { CheckboxGroup } from '@hamur/react/checkbox-group'
const apples = [
{ value: 'fuji-apple', label: 'Fuji' },
{ value: 'gala-apple', label: 'Gala' },
{ value: 'granny-smith-apple', label: 'Granny Smith' },
]
export default function CheckboxGroupParentExample() {
const [value, setValue] = React.useState<string[]>([])
return (
<CheckboxGroup
aria-labelledby="apples-caption"
className="checkbox-tree"
allValues={apples.map((apple) => apple.value)}
value={value}
onValueChange={setValue}
>
<label className="row" id="apples-caption">
<Checkbox.Root className="checkbox" parent>
<Checkbox.Indicator className="checkbox-indicator">
<span className="checkbox-check">✓</span>
<span className="checkbox-dash">–</span>
</Checkbox.Indicator>
</Checkbox.Root>
Apples
</label>
{apples.map((apple) => (
<label className="row nested" key={apple.value}>
<Checkbox.Root className="checkbox" value={apple.value}>
<Checkbox.Indicator className="checkbox-indicator">✓</Checkbox.Indicator>
</Checkbox.Root>
{apple.label}
</label>
))}
</CheckboxGroup>
)
}
Nested
A parent checkbox controls a nested group of parents and children.
CheckboxGroupNested.tsx
import * as React from 'react'
import { Checkbox } from '@hamur/react/checkbox'
import { CheckboxGroup } from '@hamur/react/checkbox-group'
const mainPermissions = ['view-dashboard', 'manage-users', 'access-reports']
const userManagementPermissions = ['create-user', 'edit-user', 'delete-user', 'assign-roles']
const management = [
{ value: 'create-user', label: 'Create User' },
{ value: 'edit-user', label: 'Edit User' },
{ value: 'delete-user', label: 'Delete User' },
{ value: 'assign-roles', label: 'Assign Roles' },
]
export default function CheckboxGroupNestedExample() {
const [mainValue, setMainValue] = React.useState<string[]>([])
const [managementValue, setManagementValue] = React.useState<string[]>([])
return (
<CheckboxGroup
aria-labelledby="permissions-caption"
className="checkbox-tree"
allValues={mainPermissions}
value={mainValue}
onValueChange={(value: string[]) => { if (value.includes('manage-users')) { setManagementValue(userManagementPermissions) } else if (managementValue.length === userManagementPermissions.length) { setManagementValue([]) } setMainValue(value) }}
>
<label className="row" id="permissions-caption">
<Checkbox.Root
className="checkbox"
parent
indeterminate={
managementValue.length > 0 &&
managementValue.length !== userManagementPermissions.length
}
>
<Checkbox.Indicator className="checkbox-indicator">
<span className="checkbox-check">✓</span>
<span className="checkbox-dash">–</span>
</Checkbox.Indicator>
</Checkbox.Root>
User Permissions
</label>
<label className="row nested">
<Checkbox.Root className="checkbox" value="view-dashboard">
<Checkbox.Indicator className="checkbox-indicator">✓</Checkbox.Indicator>
</Checkbox.Root>
View Dashboard
</label>
<label className="row nested">
<Checkbox.Root className="checkbox" value="access-reports">
<Checkbox.Indicator className="checkbox-indicator">✓</Checkbox.Indicator>
</Checkbox.Root>
Access Reports
</label>
<CheckboxGroup
aria-labelledby="manage-users-caption"
className="checkbox-tree nested"
allValues={userManagementPermissions}
value={managementValue}
onValueChange={(value) => {
if (value.length === userManagementPermissions.length) {
setMainValue((prev) => Array.from(new Set([...prev, 'manage-users'])))
} else {
setMainValue((prev) => prev.filter((v) => v !== 'manage-users'))
}
setManagementValue(value)
}}
>
<label className="row" id="manage-users-caption">
<Checkbox.Root className="checkbox" parent>
<Checkbox.Indicator className="checkbox-indicator">
<span className="checkbox-check">✓</span>
<span className="checkbox-dash">–</span>
</Checkbox.Indicator>
</Checkbox.Root>
Manage Users
</label>
{management.map((permission) => (
<label className="row nested" key={permission.value}>
<Checkbox.Root className="checkbox" value={permission.value}>
<Checkbox.Indicator className="checkbox-indicator">✓</Checkbox.Indicator>
</Checkbox.Root>
{permission.label}
</label>
))}
</CheckboxGroup>
</CheckboxGroup>
)
}
API reference
5 props across 1 parts, in React syntax. className, style, render are listed once, under Shared props.
CheckboxGroupCheckboxGroup
Provides a shared state to a series of checkboxes.
Shared props
Every part that renders an element takes these.
Keyboard and accessibility
Keyboard
Each checkbox keeps its own keys (Space toggles it); the group adds none.
Accessibility
Focus order
- Each checkbox is its own tab stop, in document order; the group adds none.