iced-swdir-tree
A batteries-included directory-tree widget for iced — lazy-loading, async, multi-select, drag-and-drop, live search.
Overview
A reusable iced widget for displaying a directory tree with
selection, lazy loading, filtering, and asynchronous traversal.
Built on swdir's scan_dir for
single-level, non-recursive directory listings — ideal for GUI
trees that expand one folder at a time.
The widget never blocks the UI thread on disk I/O; it never
touches the filesystem beyond reading directory listings; and it
ships its full event surface (selection, drag-drop, keyboard,
search) behind a small, typed API that composes with the iced
Task / Subscription model.
When to use it
Reach for this crate when your iced app needs any of:
- A file/folder picker with multi-select.
- A project-navigator pane (code editor, asset browser, file-manager side panel).
- Drag-and-drop between folders — you react to a
DragCompleted { sources, destination }event and perform the move/copy/upload yourself. - A searchable directory view with real-time type-ahead filtering.
If you only need a one-shot "pick a file" dialog, the OS-native file-chooser is almost certainly a better fit.
Quick start
[]
= "0.14"
= "0.6"
use PathBuf;
use ;
use ;
For real lucide glyphs instead of the Unicode-symbol fallback,
enable the icons feature and register the bundled font:
= { = "0.6", = ["icons"] }
application
.font
.run
Working apps live in examples/: keyboard_nav,
multi_select, drag_drop, search. Run them with
cargo run --example <name>.
Design notes
- Lazy, async, cache-backed. Only the root is eagerly
created. Each expansion dispatches a scan through a pluggable
ScanExecutorand merges the result back into a generation-tagged cache. Filter changes and search re-derive from the cache — no re-scan. - Every feature is orthogonal. Selection survives filter flips, subtree reloads, collapse/re-expand cycles, and search-hidden rows. Drag state is separate from selection state. Search doesn't mutate expansion. These invariants are tested (the crate ships 140+ tests).
- The widget owns UI state, not filesystem state. It never
renames, deletes, moves, or writes. Drag-and-drop produces a
DragCompletedevent for your app to handle — the widget's job ends at "here's what the user asked for." - Safety valves where defaults matter. Prefetch
(
with_prefetch_limit) won't enter.git,node_modules,target, or other common "don't scan this" directories out of the box; the skip list is configurable.max_depthcaps recursion. Generation tags drop stale scan results that returned after a collapse.
Documentation
📚 Full reference in docs/, organized by intent:
- Guide (build something) — Configuration · Multi-select · Drag-and-drop · Keyboard navigation · Incremental search · Parallel pre-expansion · Custom scan executor
- Reference (look something up) — Features · Events
- Internals (understand or contribute) — Architecture · Development & testing
- Release notes — CHANGELOG · ROADMAP