shadcn.io is not affiliated with official shadcn/ui
Nested Task Tree Block for React
A three-level task outline with tri-state parent boxes, an N of M count on every branch, Expand all and Collapse all, and Indent and Outdent by button or Shift plus arrow key.
Installation
Overview
Lay out a project as a tree, with this nested to-do list block for React with Base UI. Tasks sit up to three levels deep. A parent's box shows a dash while some of the tasks under it are done, ticking it ticks everything below, and each branch carries "5 of 9" beside its title. The toolbar has Expand all, Collapse all, Indent and Outdent, which act on the selected row; Indent and Outdent stay inert at the limits and the status line says why ("Branches stop at three levels."). Each row's title is also the keyboard handle: Up and Down move between rows, Right and Left open and close a branch, and Shift plus Right or Left indents or outdents it. The outline is a plain list with a roving tab stop and a Button chevron on each branch, so it works the same on every base. The frame is ruled by Guides. For project outlines, work breakdowns and checklists with groups.
FAQ
How do I load my own tree?
Replace START with a flat array in display order. Each row has an id, a title, a done flag, an open flag and a depth of 0 to 2; a row's children are the rows after it with a greater depth. Counts and the dash are worked out from that order, so nothing else is stored.
Which keys does it use?
Up and Down move between visible rows, Right opens a closed branch and Left closes an open one, and Shift+Right and Shift+Left indent and outdent the row with its branch. Right and Left swap in a right-to-left page. Only the selected row is in the tab order, so Tab passes through the outline in one stop.
When can a row not move?
Indent needs a row above it at the same or a deeper level to go under, and the whole branch has to stay within three levels. Outdent needs the row to be below the top level. The buttons use aria-disabled and the status line gives the reason when you press one.