tui-file-explorer
Keyboard-driven, multi-pane file manager for Ratatui. Install the standalone tfe CLI, or embed FileExplorer, DualPane, or the complete App in an existing Ratatui event loop. See Library quick start.
Preview
Dynamic multi-pane layout
Multi-pane file operations
Basic navigation
Theme switcher
Fuzzy finder
Undo and redo
Size info on and off
Bulk rename
Bookmarks
Git change markers
Archive preview and extract
Preview and inline editor
Picture preview
Search
Sort modes
Extension filter
File operations
Pane toggle
Dual-pane widget
Options panel
Editor picker
Create entries
Features
- Dynamic multi-pane layout —
Tab/Shift+Tabcycle focus,Ctrl+Topens a pane,Ctrl+Wcloses one, andwtoggles focused single-pane mode. - File operations — mark multiple entries, copy, move, recursively delete, create, rename, and confirm overwrites.
- Fast navigation — arrows, Vim keys, paging, top/bottom jumps, incremental search, extension filters, and three sort modes.
- Find, bookmark, undo — recursive fuzzy finder (
f), bookmarks (b/Shift+B), undo/redo (u/Ctrl+R), and bulk rename (Shift+R). - Git and archives — change markers next to entries (
v), archive listings in the preview, and one-key extraction (Shift+X). - Never blocks — previews, folder sizes, git status, searches and slow directory reads run on background threads.
- Configurable — every key can be rebound in
keymap.toml; size info, trash and git markers are switchable via keys, flags and settings. - Preview and editing — text with line numbers, images, binary hex dumps, directory summaries, external editors, and a built-in editor.
- Terminal-native images — Kitty, Sixel, iTerm2, and halfblock fallback through
ratatui-image. - 43 themes — live theme picker plus fully customizable
Themevalues. - Persistent CLI state — pane directories, active pane, theme, sort mode, visibility settings, editor, and cd-on-exit.
- Cross-platform shell integration — bash, zsh, fish, PowerShell, and Nushell on macOS, Linux, and Windows.
- Optional shared theming — enable the
themefeature fortui-nuancesintegration (off by default). - Three library tiers —
FileExplorer,DualPane, or fullApp.
Installation
Library
[]
= "3"
= "0.30"
Choose only the layers your application needs:
[]
# Lightweight FileExplorer + DualPane widgets
= { = "3", = false }
# Full embeddable App, without the tfe binary or Clap
= { = "3", = false, = ["full-app"] }
| Feature | Adds |
|---|---|
preview |
Image/text/binary/directory/archive preview (loaded on a background thread); implies archive |
archive |
.zip / .tar / .tar.gz listing and path-traversal-safe extraction |
persistence |
Serde-backed AppState loading and saving, keymap.toml parsing |
trash |
TrashFileSystem + AppOptions::use_trash: deletions go to the OS trash / recycle bin |
full-app |
Complete App, panels, operations, preview, and persistence |
cli (default) |
tfe binary and Clap argument parsing |
CLI
Library quick start
tui-file-explorer is designed for library use as well as the standalone CLI; no separate library crate is required. Choose the state/rendering layer that fits your host application, create it once, render it inside Terminal::draw, and forward keyboard events from your existing event loop. Use default-features = false when the tfe binary and clap are not needed.
| API | Use when | Provides |
|---|---|---|
FileExplorer |
You want one browser widget | Navigation, filtering, sorting, marks, create, rename |
DualPane |
You want a focused two-pane widget | Two independent FileExplorers, focus switching, single/dual toggle |
App + draw |
You want the complete tfe experience |
Arbitrary panes, file operations, panels, preview, editors, persistence-ready state |
Full app
use PathBuf;
use ;
let mut app = new;
loop
# Ok::
If your application already owns terminal events and layout, use dispatch_event plus draw_in:
let outcome = app.dispatch_event?;
terminal.draw?;
match outcome
AppViewOptions controls action/debug bars, panel widths, preview allocation, minimum pane width, and HintLayout. Its default Auto mode stacks action hints vertically below 90 columns. AppCommand and KeyBindings support command palettes and custom shortcuts without replacing the state machine. See the complete embed example.
Single-pane widget
use ;
let mut explorer = builder
.allow_extension
.allow_extension
.show_hidden
.show_sizes // file + folder size column
.show_dir_sizes // folders show item counts, no recursive walk
.sort_mode
.build;
terminal.draw?;
match explorer.handle_key
# Ok::
Dual-pane widget
use PathBuf;
use ;
let mut dual = builder
.right_dir
.show_hidden
.build;
terminal.draw?;
match dual.handle_key
# Ok::
Custom backends implement FileSystem and are passed through FileExplorerBuilder::filesystem, DualPaneBuilder::filesystem, or PaneOptions::filesystem. Checked construction and reload are available through try_build and try_reload.
For non-blocking copy, move, and delete, set OperationMode::Deferred. dispatch_key then returns AppOutcome::OperationRequested; execute it on a worker with execute_operation_with_progress (or execute_operation_with for a custom filesystem), feed progress through apply_operation_progress, and finish with apply_operation_result. Operation IDs reject stale progress/results, and cancel_operation invalidates late worker responses.
Host-owned persistence uses app.snapshot(), app.restore(...), load_state_from, and save_state_to.
See examples/ and the complete API on docs.rs.
Theming
Theming is shared with the other components by the same author through
tui-nuances (git dependency
until it is published). This is optional and requires the theme feature
(not enabled by default, so no extra dependency otherwise):
= { = "3", = ["theme"] }
The explorer keeps its own nine-colour Theme as the
style type; it maps from a shared NuancesTheme (re-exported
tui_nuances::Theme). Without a theme the default look is unchanged.
use Color;
use ;
let shared = by_name.unwrap_or_default;
// terminal.draw(|f| render_nuanced(&mut explorer, f, f.area(), &shared));
let theme: Theme = .into; // From<&NuancesTheme>
// Explicit colours win over the theme, in any call order:
let tuned = new.theme.brand.build;
Role mapping: brand←title, accent←accent, success/match_file←success,
dim←muted, fg←foreground, sel_bg←selection_bg, dir←primary,
bg←background. To pass your app's theme, implement ThemeProvider
(Theme::from_provider(&app_theme)) or impl From<&AppTheme> for NuancesTheme.
AppBuilder::theme accepts anything Into<Theme>, including &NuancesTheme.
With --features theme, the basic, dual_pane and theme_switcher examples cycle shared themes with t / T (theme_switcher requires it).
Keyboard controls
| Area | Keys | Action |
|---|---|---|
| Navigation | ↑/k, ↓/j |
Move cursor |
| Navigation | ←/h/Backspace |
Ascend to parent |
| Navigation | → |
Descend into directory; move down when entry is a file |
| Navigation | Enter/l |
Descend or confirm file |
| Navigation | PgUp/PgDn, g/G |
Page, top, bottom |
| Panes | Tab/Shift+Tab |
Next/previous pane |
| Panes | Ctrl+T/Ctrl+W |
Open/close pane |
| Panes | w |
Toggle focused single-pane/multi-pane layout |
| Search | /, Backspace, Esc |
Start, edit, or cancel incremental search |
| View | s, ., z, Shift+Z |
Cycle sort, toggle hidden entries, toggle all size info, toggle recursive folder sizes (off = item counts, no directory walk) |
| Selection | Space |
Mark/unmark current entry |
| File operations | x, p, d |
Cut, paste, delete |
| File operations | n, N, r |
New directory, new file, rename |
| File operations | Shift+R |
Bulk rename: edit all (or marked) names in your editor, one per line |
| File operations | u, Ctrl+R |
Undo / redo the last rename / create / move / copy / bulk rename / extract (and trash-deletes where the OS trash can restore) |
| Find | f |
Recursive fuzzy finder; Enter jumps to the match |
| Bookmarks | b, Shift+B |
Bookmark the current folder; open the bookmark list (Del removes one) |
| Git | v |
Toggle git change markers (M A ? D R U; folders show their children's state) |
| Archives | Shift+X |
Extract the highlighted .zip / .tar / .tar.gz / .tgz into a sibling folder; the preview lists archive contents |
| Preview | P, Ctrl+J/Ctrl+K |
Toggle and scroll preview |
| Editors | e, i, Shift+E |
External editor, inline editor, editor picker |
| Panels | T, Shift+O |
Theme picker, options panel |
| Theme | t, [ |
Next/previous theme |
| Shell | Shift+C |
Toggle cd-on-exit |
| Exit | Esc/q, Ctrl+C |
Dismiss or exit |
Search and text-input modes consume printable keys before global shortcuts. Delete and overwrite operations require confirmation.
CLI usage
tfe [OPTIONS] [PATH]
Common options:
| Option | Description |
|---|---|
-e, --ext <EXT> |
Restrict selectable files by extension; repeatable |
-H, --hidden |
Show dotfiles on startup |
-t, --theme <THEME> |
Select persisted or named theme |
--list-themes |
Print all theme names |
--show-themes |
Open theme picker at startup |
--single-pane |
Start with only focused pane visible |
--sizes / --no-sizes |
Show / hide all file and folder size info (persisted) |
--trash / --no-trash |
Send deletions to the OS trash (default) or delete permanently (persisted) |
--git / --no-git |
Show / hide git change markers (persisted) |
--dump-keymap |
Print a complete keymap.toml with the built-in bindings |
--dir-sizes / --no-dir-sizes |
Compute / skip recursive folder sizes; off shows item counts (persisted) |
--editor <EDITOR> |
Select external editor or command |
--cd / --no-cd |
Enable/disable persisted cd-on-exit |
--init <SHELL> |
Install shell wrapper |
--print-dir |
Print selected file's parent directory |
-0, --null |
Use NUL-delimited output |
--info / --doctor |
Show environment info or run diagnostics |
-v, --verbose |
Enable startup logs, log file, and debug panel |
Run tfe --help for full option documentation.
Custom key bindings
Every binding can be changed in keymap.toml (next to settings.json; tfe --info shows the directory). Start from tfe --dump-keymap > keymap.toml:
[] # per-pane navigation
= ["up", "k"]
= ["esc"] # drops the default `q`
[] # app-wide commands
= ["u", "ctrl+z"]
= ["ctrl+r"]
= ["m"] # `x` stops cutting
A command listed in the file replaces all of its default keys; commands you do not list keep theirs. Keys are single characters or esc enter tab backspace up down left right home end pageup pagedown space f1…f24 with ctrl+, alt+ or shift+ prefixes. Mistakes (unknown command, bad key) are reported on stderr and skipped — they never stop tfe from starting.
Embedding apps get the same machinery through Keymap / FileExplorerBuilder::keymap(..) and KeyBindings::remap(..), or App::apply_keymap_config(..).
Shell integration
tfe renders on stderr and reserves stdout for selected paths, cd-on-exit, and one-time shell setup. Enable directory changes and install the wrapper once:
Source the file reported by --init, or open a new terminal. Afterwards, dismissing with Esc/q changes the parent shell to the active pane's directory.
Use command tfe to bypass the wrapper when piping output:
|
|
Exit codes:
| Code | Meaning |
|---|---|
0 |
Selection or successful cd-on-exit output |
1 |
Dismissed without cd-on-exit output |
2 |
Invalid arguments or I/O failure |
Main capabilities
Multi-pane workflow
A fresh CLI session starts with two panes; later sessions restore the persisted pane layout. Each pane keeps its own directory, cursor, marks, search, sort, and size-display state. New panes clone the active pane's directory and display settings; at least one pane always remains open.
Typical source-to-destination copy:
- Mark one or more entries with
Space. - Move to another pane with
Tab, or create one withCtrl+T. - Navigate to destination.
- Press
pto copy. Usexbefore switching panes for a move.
Search, filtering, and sorting
/starts case-insensitive incremental filename search.Escclears active search before dismissing explorer.- Extension filters dim non-matching files while leaving directories navigable.
scyclesName → Size ↓ → Extension.- Directories remain grouped before files.
Preview and editors
P opens preview for text, supported images (PNG, JPEG, GIF, BMP, WebP), binary files, and directories. i opens built-in text editor; Ctrl+S saves and Esc returns. e launches configured external editor.
Themes
Use t/[ to cycle or T to open picker. Forty-three presets include Catppuccin, Dracula, Nord, Solarized, Gruvbox, Tokyo Night, Kanagawa, Rosé Pine, Flexoki, and others. Customize every color with Theme builder methods.
Examples
| Example | Command | Purpose |
|---|---|---|
| Basic widget | cargo run --example basic |
Navigation, search, sorting, extension filters |
| Dual pane | cargo run --example dual_pane -- /tmp |
DualPane library API and independent directories |
| Theme switcher | cargo run --example theme_switcher |
Live preset switching |
| Options | cargo run --example options |
Options and editor panels |
| Editor picker | cargo run --example editor_picker |
Terminal and GUI editor selection |
| Open file | cargo run --example open_file -- "code --wait" |
Suspend TUI, edit, resume |
| Create entries | cargo run --example create_entries |
Create directories/files and rename entries |
| Full app | cargo run --example full |
Complete App integration |
| Embedded app | cargo run --example embed |
draw_in, host layout, outcomes, key remapping, deferred operations |
Public API
Main re-exports:
| Group | Items |
|---|---|
| Single pane | FileExplorer, FileExplorerBuilder, ExplorerCommand, ExplorerOutcome, SelectionMode, FsEntry, SortMode, render, render_themed |
| Dual pane | DualPane, DualPaneBuilder, DualPaneActive, DualPaneCommand, DualPaneOutcome, render_dual_pane, render_dual_pane_themed |
| Full app | App, AppBuilder, PaneOptions, AppOutcome, AppEvent, AppCommand, KeyBindings, draw, draw_in, AppViewOptions, HintLayout |
| Operations | FileOperation, OperationRequest, OperationProgress, OperationResult, OperationMode |
| Filesystems | FileSystem, StdFileSystem, SharedFileSystem, ExplorerError |
| Preview/editor | PreviewState, PreviewContent, InlineEditor, EditorAction, render_preview, render_inline_editor |
| Theme/utilities | Theme, entry_icon, fmt_size, copy_dir_all, AppState, load_state, save_state |
Modules and detailed method docs: docs.rs/tui-file-explorer.
Demo recordings
Install VHS, then run:
Tapes live in examples/vhs/. Generated 1600×900 GIFs live in examples/vhs/generated/ and are tracked with Git LFS.
| Tape | Demonstrates |
|---|---|
multi_pane |
Dynamic pane creation/closing, focus cycling, single-pane focus |
multi_pane_file_ops |
Copying marked files between three panes |
basic, search, sort, filter |
Core navigation and discovery |
file_ops, create_entries |
Copy/move/delete and create/rename workflows |
preview, picture_preview |
Text, binary, directory, and image preview |
theme_switcher, options, editor_picker |
Themes and configuration panels |
pane_toggle, dual_pane |
CLI layout and DualPane library widget |
Troubleshooting
Use command tfe when diagnostics or pipelines must bypass installed shell wrapper.
Development
Requires Rust 1.90 or newer. Optional tooling: just, git-cliff, and vhs.
Fuzzing (requires nightly and cargo install cargo-fuzz):
Contributions are welcome; see CONTRIBUTING.md.
License
MIT — see LICENSE.
Acknowledgments
Built for the Ratatui ecosystem.