HextaUI

Checkbox: Nested groups

Groups nest. Each parent reflects the state of the group directly below it, and the top parent covers everything.

"use client"

import * as React from "react"

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

const userPermissions = ["users.read", "users.write", "users.delete"]
const billingPermissions = ["billing.read", "billing.write"]

export function CheckboxNestedGroups() {
  const [users, setUsers] = React.useState<string[]>(["users.read"])
  const [billing, setBilling] = React.useState<string[]>([])

  return (
    <div className="text-sm">
      <CheckboxGroup
        aria-label="Permissions"
        value={[...users, ...billing]}
        onValueChange={(next) => {
          setUsers(next.filter((value) => value.startsWith("users.")))
          setBilling(next.filter((value) => value.startsWith("billing.")))
        }}
        allValues={[...userPermissions, ...billingPermissions]}
      >
        <label className="flex items-center gap-3">
          <Checkbox parent />
          All permissions
        </label>
        <div className="flex flex-col gap-3 ps-7">
          <CheckboxGroup
            aria-label="Users"
            value={users}
            onValueChange={setUsers}
            allValues={userPermissions}
          >
            <label className="flex items-center gap-3">
              <Checkbox parent />
              Users
            </label>
            <div className="flex flex-col gap-3 ps-7">
              {userPermissions.map((permission) => (
                <label key={permission} className="flex items-center gap-3">
                  <Checkbox value={permission} />
                  {permission}
                </label>
              ))}
            </div>
          </CheckboxGroup>
          <CheckboxGroup
            aria-label="Billing"
            value={billing}
            onValueChange={setBilling}
            allValues={billingPermissions}
          >
            <label className="flex items-center gap-3">
              <Checkbox parent />
              Billing
            </label>
            <div className="flex flex-col gap-3 ps-7">
              {billingPermissions.map((permission) => (
                <label key={permission} className="flex items-center gap-3">
                  <Checkbox value={permission} />
                  {permission}
                </label>
              ))}
            </div>
          </CheckboxGroup>
        </div>
      </CheckboxGroup>
    </div>
  )
}

This adds the example as components/examples/checkbox/nested-groups.tsx, together with the Checkbox component and the HextaUI theme tokens it needs.

pnpm dlx shadcn@latest add https://hextaui.com/r/checkbox-nested-groups.json

To add only the component, follow the Checkbox installation.

Props in this example

The Checkbox props this example sets, from the API reference.

PropTypeDefault
valueIdentifies the box inside a group and is what the form submits. Falls back to name, then “on”.
string–
parentControls every value in the group’s allValues. Only inside a CheckboxGroup.
booleanfalse
PropTypeDefault
valueValues of the ticked checkboxes.
string[]–
onValueChange
(value: string[], details) => void–
allValuesEvery value in the group. Required for a parent checkbox.
string[]–

Every prop is in the Checkbox API reference.

See them all, with keyboard support and accessibility notes, on the Checkbox page.