FAQ
How do I get the IDs of the checked nodes?
Use getSelectedIDs with the tree from onChange. Choose mode: 'leaves' for only bottom-level nodes, or 'topmost' to let a fully checked parent stand in for its subtree. See Reading the selection.
How do I pre-select nodes?
Set valueProperty on the nodes in your data before passing it in, for example included: true. With chained selection, set the parents' values to match their children (true, or null for mixed), because TreeSelect only recalculates parents when a node changes.
How does the indeterminate (mixed) state work?
A parent is mixed (null) when some, but not all, of its descendants are checked. The checkbox shows a square, the input's indeterminate property is set, and screen readers announce the node as partially checked. See Selection.
Can I use it without Tailwind CSS?
Yes. Import @attebyte/react-tree-select/style.css for the default styles, and pass your own class names or style objects. Tailwind is only needed if you want to style it with Tailwind classes.
Does importing the stylesheet affect the rest of my app?
No. Every class in it is prefixed with rts:, so it only matches the tree's own elements, and its rules are in the components cascade layer, so your own styles take priority. It has no global resets and doesn't declare theme variables that could override your own Tailwind theme. (Version 2.0.0 had a bug where its utility classes could override identically named classes in your app; upgrade to 2.1.0 or later.)
Does it support server-side rendering?
Yes. Both controlled and uncontrolled trees render on the server, including Next.js and other React frameworks. The tree is fully interactive once hydrated.
Why doesn't changing defaultData update the tree?
defaultData is only the starting value, like defaultValue on an <input>: after the first render the tree keeps its own state, so the user's selections aren't wiped out when your component re-renders. To change the data from outside, either control the tree with data and onChange, or give it a new key when new data arrives, which remounts it with the new defaultData:
<TreeSelect key={dataVersion} defaultData={categories} {...props} />
defaultExpanded is the exception: changing it later expands or collapses every node.
Does the data have to be an array?
No. If your tree has a single root node, pass the node itself to data or defaultData. onChange then reports a single node instead of an array, and getSelectedIDs accepts either shape.
Which versions of React are supported?
React 18 and React 19.
Can it load children lazily?
TreeSelect renders the data you pass. To load children on demand, use controlled usage: when a node is expanded in your custom node component (onExpandedChange), fetch its children and add them to your state.
Why is a parent mixed even though all of its enabled children are checked?
One of its children is disabled and unchecked. A parent is only checked when everything under it is checked. Clicking it again unchecks its enabled children. See Disabled nodes.