A parent checkbox needs a third state for partial selection
Aliases: indeterminate · mixed checkbox · partial check
What it is
When a parent checkbox summarises children, and some children are ticked while others are not, the parent cannot show ordinary on or off. It needs a third indeterminate (mixed) state. The meaning is “this group is mixed right now,” not “the parent is half selected.” Without the third state the parent can only lie: drawing it ticked implies every child is in; drawing it empty implies every child is out. Partial selection is a real set state and needs its own appearance.
The third state is a summary, not another independent value to submit. What still matters at submit is each child’s boolean, and — if the model needs it — the parent node’s own boolean.
Why it happens
People treat the parent box as a folded view of the set. Two-state booleans cannot encode three sets: empty, full, proper subset. Forcing the subset into two states maps it onto empty or full, so a scan of the folded tree fights the facts after expand. Once that fight is noticed, people stop trusting any layer’s tick and open every row; the summary control has lost its reason to exist.
Indeterminate makes the summary isomorphic: all empty → unchecked, all full → checked, otherwise mixed. When children expand, the parent’s mixed should be explained by those ticks, not by a hidden “half-selected” bit on the parent. In a deep tree every layer uses the same summary rule, and mixed bubbles: grandchildren mixed make the child mixed, children mixed make the parent mixed.
Where it stops holding
A flat list with no children does not need a third state; a dash on an ordinary item looks like a broken widget. If the parent is its own object in the model (selecting a folder is not selecting the files inside), mixed only describes “are the children consistent”; do not let it impersonate “the parent node is selected.” When every child is disabled, mixed has no operational meaning; disable the parent and explain. Radio groups have no mixed: an exclusive set never reaches “some are true.”
Applying it
- Whenever a parent visually summarises children, give inconsistency a mixed state; do not draw mixed as full or empty.
- Let mixed bubble up so a folded summary matches the children after expand.
- Keep submit and APIs on the leaves (and the parent node itself when needed); do not write mixed as a third boolean.
- How to check: tick some children, fold the parent. The parent is neither empty nor a tick, and expanding explains the mix. If the parent shows fully ticked, the third state was absent.