Build a nested checkbox tree where parents and children stay in sync. Toggling a parent cascades down to every descendant; a parent's own state is derived up from its children — checked when all are checked, unchecked when none are, and indeterminate (the dash) when only some are. The clean way to keep this consistent is to store one source of truth — the checked leaves — and derive every folder from them.
type Node = { id: string; label: string; children?: Node[] };
// A self-contained component. No props.
function App(): JSX.Element;
check "Citrus" → Orange ✓ and Lemon ✓ (cascade down)
uncheck "Orange" → Citrus becomes ▣ indeterminate (some, not all)
check "Orange" again → Citrus ✓ (all children checked)
checking all of Apple, Banana, Orange, Lemon → "Fruits" ✓
unchecking any one → "Fruits" ▣ indeterminate
Set of checked leaf ids; folders are derived, never stored.indeterminate is a property. It can't be set via HTML attribute — set the DOM property with a ref.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.