React Tree View: Checkboxen, Lazy Loading, Drag and Drop

Du brauchst eine React Tree View für Ordner, Produktkategorien oder einen Screen für Berechtigungen. Eine rekursive Komponente mit Chevron und etwas Einrückung steht in zehn Minuten. Dann kommen die Anforderungen: Eine Checkbox an einem Ordner soll alles darunter abhaken, ein Zweig mit 2.000 Kindern soll erst laden, wenn er aufgeht, ein Filter soll „invoice“ drei Ebenen tief finden, jemand will eine Datei in einen anderen Ordner ziehen, und das Ganze muss mit Pfeiltasten und auf dem Smartphone funktionieren. Dieser Guide zeigt, was ein Baum für die Produktion braucht, wie die gängigen Optionen im Vergleich abschneiden und welche Props in der Tree View von Wingo UI zählen, mit funktionierendem Code für jeden Teil.
Was muss eine React Tree View können?
Sieben Dinge. Eine rekursive Komponente mit Chevron deckt nur das Erste ab:
- Auf- und Zuklappen mit einer Animation, die die Seite nicht springen lässt.
- Tastaturnavigation nach dem WAI-ARIA-Muster für Tree Views (opens in a new tab): ein einziger Tab-Stopp, Pfeiltasten zum Bewegen, Rechts zum Öffnen, Links zum Schließen oder Springen zum Elternknoten, Type-ahead.
- Auswahl, einfach oder mehrfach, getrennt vom Abhaken.
- Tri-State-Checkboxen, bei denen ein teilweise abgehakter Ordner einen Strich zeigt.
- Lazy Loading der Kinder beim ersten Aufklappen, mit Ladezustand und einer Möglichkeit, es erneut zu versuchen.
- Ein Filter, der die Eltern jedes Treffers behält, damit du siehst, wo er liegt.
- Drag and Drop zum Verschieben, dazu ein Weg, dieselbe Verschiebung per Tastatur zu machen.
Das Smartphone bringt zwei weitere mit: Zeilen, die groß genug zum Antippen sind, und ein Zeilenmenü, das als Bottom Sheet aufgeht statt als winziges Popover.
Wie schneiden die React-Tree-View-Libraries im Vergleich ab?
Die Libraries für eine React Tree View Komponente unterscheiden sich bei drei Features: Lazy Loading der Kinder, Drag and Drop und Checkboxen. Bei MUI X gehören Lazy Loading und Umsortieren zum kostenpflichtigen Pro-Paket, react-arborist bringt Drag and Drop und einen Filter mit, aber seine README erwähnt keine Checkboxen, und shadcn/ui hat überhaupt keine Baum-Komponente, nur einen Sidebar-Block. Die Fakten stammen aus der öffentlichen Doku und den READMEs der Projekte, Stand Oktober 2026.
Läuft deine App schon mit MUI, ist die kostenlose RichTreeView mit Checkbox-Auswahl der kürzere Weg. Willst du einen kostenlosen, virtualisierten Baum und stylst ihn gern selbst, passt react-arborist gut. Wer nach „react tree view shadcn“ sucht, will meist Code, der im eigenen Repo liegt: ReUI, shadcn-tree-view (opens in a new tab) (MIT, mit Drag and Drop) und die Tree View von Wingo UI installierst du alle als Quellcode. Der Rest dieses Guides behandelt die Komponente von Wingo UI.
Was braucht die Tree View zum Rendern?
Ein items-Array mit verschachtelten Knoten. Jeder Knoten hat eine id, die im ganzen Baum eindeutig ist, ein label und optional children.
So sieht ein React File Tree aus, wie ihn React-Entwickler kennen: folderIcons gibt Elternknoten ein Ordner-Icon, das mit ihnen aufgeht, und Blättern ein Datei-Icon. onAction läuft, wenn du eine Datei mit Enter, per Doppelklick oder auf dem Smartphone per Tap öffnest. Ohne onAction folgt ein Knoten mit href seinem Link. Ein Knoten kann außerdem icon, badge, description, disabled und eigene actions für das ⋯-Menü tragen, im selben Format wie die Einträge im Dropdown Menu.
Deine Daten kommen vermutlich als flache Zeilen mit parentId aus der Datenbank. Wandle sie einmal um:
Wie funktionieren Tri-State-Checkboxen in einer React Tree View?
Schalte checkboxes ein und halte checkedKeys im State. Mit cascade (standardmäßig an) hakt ein Klick auf einen Ordner jeden geladenen, aktivierten Knoten darunter mit ab. Ein Ordner gilt als abgehakt, wenn alle seine Kinder es sind, und zeigt einen Strich, wenn nur ein Teil es ist. Deaktivierte Zeilen werden übersprungen, damit Berechtigungen wie „nur Owner“ leer bleiben, wenn jemand die ganze Gruppe abhakt. Die Zeilen melden den Zustand als aria-checked, mit mixed für den Strich.
Ein React Tree View Checkbox-Setup für einen Rollen-Editor sieht so aus:
Abhaken und Auswählen sind getrennt. Die Box hakt ab, die Zeile wählt aus. Mit selectionMode="none" hakt ein Klick auf eine Dateizeile sie auch ab, während ein Klick auf eine Ordnerzeile sie nur öffnet. Genau das willst du auf einer Seite für Berechtigungen. Um den Zustand eines Ordners auf dem Server nach derselben Regel zu berechnen, nimm das exportierte getCheckedState(node, checkedKeys).
Hak in der Demo unten den Ordner Invoices 2026 ab, nimm dann bei einer seiner Dateien den Haken wieder raus und sieh zu, wie der Ordner einen Strich bekommt. Tipp etwas ins Filterfeld, um den Baum einzugrenzen.
$ npx wingo-ui@latest add tree-viewWie lade ich Kinder per Lazy Loading?
Markier einen Knoten mit hasChildren und lass children weg. Beim ersten Aufklappen ruft der Baum loadChildren(node) auf und zeigt eine Zeile mit Spinner. Schlägt das Promise fehl, tritt eine Retry-Zeile an ihre Stelle. Die Ergebnisse speichert der Baum intern zwischen.
Unterordner, die du noch nicht geholt hast, können mit hasChildren: true zurückkommen. Eine Grenze solltest du einplanen: Der Filter sieht nur geladene Knoten. Ist der Großteil des Baums noch nicht geladen, such auf dem Server und zeig stattdessen die Ergebnisse.
Wie funktioniert der Filter?
searchable setzt ein Filterfeld über den Baum. Treffer behalten ihre Eltern, der Pfad zu jedem Treffer geht auf, und die passenden Buchstaben werden fett. Groß- und Kleinschreibung und diakritische Zeichen spielen nie eine Rolle, „skoda“ findet also „Škoda“. Die Eingabe wird um 150ms entprellt (Debounce). ArrowDown springt vom Feld in den Baum, und Escape leert es. Auf dem Smartphone nutzt das Feld 16px Schrift, damit iOS Safari beim Fokussieren nicht hineinzoomt.
Du kannst den Text mit filter und onFilterChange steuern, etwa um ihn in der URL zu halten. Ein Knoten, dessen label JSX ist, braucht einen textValue, sonst haben Filter und Type-ahead nichts, womit sie vergleichen können.
Wie baue ich Drag and Drop in eine React Tree View ein?
Schalte draggable ein und verarbeite onMove. Eine Linie zeigt, wo die Zeile landet: vor oder nach einer Zeile oder als Ring um einen Ordner, in den sie hineingeht. Bleibst du über einem geschlossenen Ordner stehen, geht er nach einer kurzen Pause auf, und einen Ordner in sich selbst abzulegen wird verweigert. Auf Touch-Geräten hebt ein langes Drücken von 250ms die Zeile an, damit ein Wischen weiterhin die Seite scrollt; der Guide zu dnd kit auf dem Smartphone erklärt, warum diese Verzögerung zählt.
Damit ist React Tree View Drag and Drop per Maus und Touch abgedeckt. Per Tastatur verschieben Alt + ArrowUp und Alt + ArrowDown die fokussierte Zeile unter ihren Geschwistern, Alt + ArrowRight schiebt sie in den Ordner darüber, und Alt + ArrowLeft holt sie eine Ebene heraus. Jede Verschiebung wird für Screenreader angesagt.
onMove bekommt { id, targetId, position, fromParentId, toParentId, index }, wobei index die Position unter den neuen Geschwistern ist. moveTreeNode wendet das auf deine Daten an und lässt unberührte Zweige, wie sie waren:
Pro Knoten hält draggable: false eine Zeile an ihrem Platz, und droppable: false verhindert, dass etwas darin landet. Mit droppable: true nimmt ein Blatt Drops an wie ein Ordner.
$ npx wingo-ui@latest add tree-viewWelche Tastenkürzel braucht eine Tree View?
Eine Tree View braucht die Tasten aus dem WAI-ARIA-Muster für Bäume: Pfeiltasten zum Bewegen und Öffnen, Home und End, Enter und Leertaste sowie Type-ahead, alles hinter einem einzigen Tab-Stopp. Der Baum hat role="tree", die Zeilen sind treeitems, und offene Ordner enthalten eine group. Im Baum gilt:
- ArrowDown / ArrowUp wechseln zwischen sichtbaren Zeilen; Home / End springen zur ersten und letzten; PageUp / PageDown springen um zehn Zeilen.
- ArrowRight öffnet einen geschlossenen Ordner oder geht in einen offenen hinein; ArrowLeft schließt einen offenen Ordner oder springt zum Elternknoten.
- Enter öffnet eine Datei oder klappt einen Ordner auf und zu; Leertaste wählt aus oder hakt ab, wenn Checkboxen an sind.
- Shift + Pfeiltasten erweitern eine Mehrfachauswahl, Ctrl + A (Cmd + A auf dem Mac) wählt jede sichtbare Zeile aus, Escape hebt die Auswahl auf.
- * öffnet jeden Ordner neben dem fokussierten, und tippst du Buchstaben, springt der Fokus zur nächsten Zeile, die damit beginnt.
- Shift + F10 oder die Kontextmenü-Taste öffnet das ⋯-Menü der Zeile.
Das folgt dem WAI-ARIA-Muster, das Type-ahead für jeden Baum empfiehlt, besonders für Bäume mit mehr als sieben Wurzelknoten. Alle Texte, auch die Ansagen beim Verschieben, stecken in labels und werden über DEFAULT_TREE_VIEW_LABELS gemergt. So übersetzt du den Baum, ohne ihn zu forken.
Wie verhält sie sich auf dem Smartphone und bei großen Bäumen?
Auf einem Touchscreen wachsen die Zeilen auf 44px, die ganze Zeile ist das Tap-Ziel, ein Tap auf eine Datei löst onAction aus, und der ⋯-Button bleibt sichtbar und öffnet ein Bottom Sheet.
Bei großen Bäumen rendert virtualize="auto" nur die Zeilen im sichtbaren Bereich, sobald mehr als 300 Zeilen sichtbar sind. Ein virtualisierter Baum ist im DOM flach, setzt aria-level, aria-setsize und aria-posinset an jeder Zeile, lässt die Animation beim Aufklappen weg und nutzt standardmäßig eine Scrollbox mit 420px Höhe. Mit maxHeight legst du deine eigene fest.
Was sind die typischen Fallstricke bei einer Tree View?
- Doppelte IDs. Auswahl, Aufklappen, Haken und Verschieben laufen alle über
id, sie muss also im ganzen Baum eindeutig sein, nicht nur unter Geschwistern. Im Entwicklungsmodus nennt eine Warnung die doppelten IDs. - Ordner-IDs aus der Kaskade speichern. Voll abgehakte Ordner stehen mit in
checkedKeys. Speicher die Blätter wie im Rollen-Editor oben, sonst muss dein Backend wissen, welche IDs Ordner sind und was sie beim Speichern enthielten. - Verschieben, ohne
itemszu aktualisieren. Der Baum wird von deinen Daten gesteuert. AktualisiertonMovedieitemsnicht, springt die Zeile zurück. - Ein Baum für zwei Ebenen. Eine Liste von Abschnitten mit je ein paar Einträgen liest sich besser als Accordion oder als Gruppe in einer Sidebar.
Wann nehme ich stattdessen den File Manager?
Wenn der Baum das Seitenpanel einer Dokumentenansicht ist. Der File Manager nimmt eine flache items-Liste aus { id, kind, name, parentId } und zeigt Ordner und Dateien als Raster oder Liste, mit einem Ordnerbaum (auf Basis der Tree View) daneben, sobald der Manager 768px breit ist. Er ergänzt Uploads mit Fortschritt, Umbenennen direkt in der Zeile, Verschieben über „Move to“, Massenaktionen und eine Suche über alle Ordner. Sein buildFolderTree macht aus der flachen Liste Knoten für die Tree View, dieselbe Aufgabe wie der Helfer toTree oben.
$ npx wingo-ui@latest add file-managerWie baue ich sie in mein Projekt ein?
Führ npx wingo-ui@latest add tree-view aus (oder file-manager). Die CLI kopiert den Quellcode nach components/ui, ergänzt die Komponenten und Hooks, die er importiert, und installiert @dnd-kit/core, @tanstack/react-virtual, motion und lucide-react. Beide sind Pro-Komponenten (Preise); die Checkbox, die sie nutzen, ist kostenlos. Weitere Deep Dives zu einzelnen Komponenten findest du in der Kategorie Komponenten-Guides und im Guide zu React-Formularkomponenten. Ist dein Baum eigentlich ein JSON-Payload, deckt der Guide zum React JSON Viewer diesen Fall ab.
Häufige Fragen
Hat shadcn/ui eine Tree-View-Komponente?
Nein, Stand Oktober 2026. shadcn/ui liefert einen Sidebar-Block mit einklappbarem Dateibaum (sidebar-11) auf Basis von Collapsible, aber keine Baum-Komponente mit Tastaturnavigation, Checkboxen oder Drag and Drop. Community-Registries wie ReUI und shadcn-tree-view von mrlightful sowie die Tree View von Wingo UI schließen diese Lücke.
Wie füge ich einer React Tree View Checkboxen hinzu?
Schalte checkboxes ein und halte checkedKeys im State. Mit cascade (Standard) hakt ein Klick auf einen Ordner alles darunter mit ab, und ein Ordner, bei dem nur ein Teil der Kinder abgehakt ist, zeigt einen Strich: den Zustand indeterminate.
Wie lade ich Kindknoten in einem React-Baum per Lazy Loading?
Markier einen Knoten mit hasChildren, lass children weg und übergib eine Funktion loadChildren, die ein Promise mit den Kindknoten zurückgibt. Die Tree View zeigt während des Ladens eine Zeile mit Spinner, eine Retry-Zeile, wenn das Promise fehlschlägt, und speichert das Ergebnis zwischen.
Wie wandle ich eine flache Liste mit parentId in einen Baum um?
Bau in einem Durchlauf eine Map von ID zu Knoten und häng dann jeden Knoten an die children seines Elternknotens oder an die Wurzelliste. Der Helfer in diesem Artikel schafft das in etwa zehn Zeilen, und buildFolderTree im File Manager macht dasselbe für seine Ordner.
Ist die Tree View von Wingo UI kostenlos?
Nein. Tree View und File Manager sind Pro-Komponenten. Checkbox und Dropdown Menu, auf denen sie aufbauen, sind kostenlos.
- Tree View
- Checkboxen
- Drag and Drop
- Barrierefreiheit
- React


