Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Permission Tree Checkbox Form Block for React

A role editor panel with a master box and three permission groups of three boxes each, where a parent shows ticked, empty or mixed and pressing it sets every child.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Show a partly chosen set honestly with this mixed checkbox form for React with Base UI. A compact header sits over a hairline frame with a plus mark on each corner. A master box heads the panel ("All permissions", "5 of 9"), and three bands follow (Projects, Billing, Members), each with a group box and its count in the heading row and three permission rows under it. A parent box is ticked when all its children are, empty when none is, and shows a bar when only some are; unticking one child turns its parent to the bar, and the master reads the nine. Pressing a parent sets every child: all on, or all off when all were on. Save and Discard stay quiet until something changed, and the foot counts the changes ("3 changes not saved yet."). It's built from the Checkbox with its mixed state, Label, Button, Shine Button and Guides. For role and permission editors, export column pickers, select-all lists and any tree of options.

FAQ

How does the mixed state work on each library?

The box takes checked and a separate indeterminate prop, so the block passes state === true and state === "indeterminate".The parent's state is always derived from its children by stateOf; it is never stored.

What does pressing a mixed parent do?

It ticks everything under it. Pressing a parent that is already ticked clears everything under it. That rule is in flipped, and the master uses the same function over all nine ids, so groups and master always agree.

How does it work with a keyboard and a screen reader?

Each box is named by its heading or row, and a mixed parent is announced as mixed. Tab runs through the master, then each group box and its children, and Space ticks. Each group is a region named by its heading, and the descriptions are read from the box, so they stay available on a phone where they are hidden visually.

How does it look on a phone?

The rows keep their boxes and names; the one-line descriptions drop out of sight but stay in the page for a screen reader. The foot is pinned to the bottom of the screen with Save and Discard side by side.

What stays local, and how do I connect it for real?

The role lives in the block's state and nothing is saved: the foot says "Saved in this demo. Nothing was sent." In your app, replace the comment in submit with a request that stores the allowed ids, and check them on the server again before granting access.

How do I connect it to react-hook-form or TanStack Form?

With react-hook-form, keep the allowed ids as one array field and call field.onChange from touch; the parents stay derived from that array, so they need no fields of their own. TanStack Form works the same way with an array field.