Skip to the solution
HardMachine Coding10 min read

Build Nested Checkboxes (tri-state)

1.1k views

The problem

Question presented to candidate: "Build a checkbox tree, like the one for picking permissions or grocery categories. Checking a parent checks everything under it, unchecking clears it, and a parent whose children are only partly checked should show the half-checked dash. Changing children must update every parent above them."

Requirements:

  • Render an arbitrarily deep tree of labelled checkboxes, indented by level.
  • Clicking a parent that is fully checked unchecks all its descendants; clicking an unchecked or partly checked parent checks all of them.
  • A parent shows checked when all its leaves are checked, unchecked when none are, and indeterminate (the dash) when some are, at every level up to the root.
  • The indeterminate look must come from the real indeterminate property of the input, so assistive technology sees a mixed state.
  • A summary line: "3 of 8 selected: Orange, Lemon, Lime".

What a strong answer should cover:

  • A single source of truth: store only the checked leaves (a Set of ids); derive every parent state from them in one post-order pass.
  • Why storing a checked flag on every node leads to drift, and how propagation down (toggle) and up (derive) both fall out of the leaf-only model.
  • indeterminate is a DOM property with no HTML attribute, so each framework sets it differently (React: ref plus effect; Vue and Angular: property binding).
  • What a native click does to an indeterminate checkbox and how that matches the rule "mixed becomes checked".
  • Complexity: O(n) per change; when to memoize.

Clarifying questions expected:

  • "When I click a partly checked parent, should it select all or clear all?"
  • "Can items be disabled, and should a parent click skip them?"
  • "Does the parent itself carry a value, or only the leaves?"

Code / implementation expected: Yes. A working recursive checkbox tree with correct tri-state behaviour.

  • React
  • Tree
  • Tri-state

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useMemo, useState } from "react";
import CheckNode from "./src/components/CheckNode";
import {
  groceries,
  initialChecked,
  computeStates,
  toggle,
  selectedLabels,
} from "./src/utils/checkTree";

export default function App() {
  // The single source of truth: a Set of checked LEAF ids.
  const [checked, setChecked] = useState(() => new Set(initialChecked));
  const { on, total, states } = useMemo(
    () => computeStates(groceries, checked),
    [checked],
  );
  const labels = selectedLabels(groceries, checked);

  return (
    <div className="app">
      <h1>Shopping list</h1>
      <ul className="checks">
        <CheckNode
          node={groceries}
          states={states}
          onToggle={(node) => setChecked((prev) => toggle(node, prev, states))}
        />
      </ul>
      <p className="summary" aria-live="polite" data-testid="summary">
        {on} of {total} selected{labels.length ? ": " + labels.join(", ") : ""}
      </p>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 82 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

Build a Calendar / Date Picker

Continue