---
title: File Browser
description: Navigate your filesystem with keyboard shortcuts
---
import { Aside, Tabs, TabItem, Steps } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import fileBrowserScreenshot from '../../../assets/screenshots/file-browser.png';
import codePreviewScreenshot from '../../../assets/screenshots/file-browser-code-preview.png';
import imagePreviewScreenshot from '../../../assets/screenshots/file-browser-image-preview.png';
import imageDetailsScreenshot from '../../../assets/screenshots/file-browser-image-scrolled.png';
import hiddenFilesScreenshot from '../../../assets/screenshots/file-browser-hidden.png';
import richPreviewScreenshot from '../../../assets/screenshots/file-browser-rich-preview.png';
import pdfPreviewScreenshot from '../../../assets/screenshots/file-browser-pdf.png';
import filterScreenshot from '../../../assets/screenshots/file-browser-filter.png';
The native interface includes a built-in file browser for quick filesystem navigation using keyboard shortcuts.
<Aside type="note">
The file browser is only available in **native mode**. It is not available when using Fuzzel mode.
</Aside>
## Overview
Navigate your filesystem directly from the launcher with fuzzy filtering, hidden file support, keyboard-driven actions, drag-and-drop to other applications, and a right-hand preview pane. Image previews scale to the largest size that fits the preview pane while keeping their aspect ratio and rescale when the window is resized; file details appear below the image and can be reached by scrolling the pane with Ctrl+J / Ctrl+K.
<Image src={fileBrowserScreenshot} alt="File browser example" width={800} />
## Activation
Start the file browser by typing one of these prefixes:
- Type `/` to browse from the root filesystem
- Type `~` to browse from your home directory
### Examples
```text
/ # Browse root directory
~ # Browse home directory
/home/user/ # Browse specific directory
~/Documents/ # Browse Documents folder
```
## Navigation
### Directory Structure
- **Directories** are listed first in accent color
- **Files** are listed after directories
- Current path shows in the input field
### Keyboard Shortcuts
| Key | Action |
|-----|--------|
| **Enter** | Navigate into directory OR run `action` on a file (`xdg-open` by default) |
| **Ctrl+Enter** | Run `secondary_action` on a file or directory (copy path by default) |
| **Tab** | Autocomplete selected entry into search bar |
| **Backspace** | On a trailing `/`, go up to the parent directory |
| **`~/`** or **`/`** after a `/` | Start over from your home directory or the root |
| **Ctrl+H** | Toggle hidden file visibility |
| **Ctrl+O** | Open the selected file or directory with `xdg-open` |
| **Ctrl+B** | Open the current directory in a file manager |
| **Ctrl+Y** | Copy the selected path to the clipboard, regardless of configured actions |
| **Ctrl+Alt+Y** | Copy a supported image file to the clipboard |
| **Ctrl+S** | Cycle the sort order: name, modified date, created date |
| **Ctrl+.** | Cycle the listing: all entries, files only, directories only |
| **Ctrl+J** / **Ctrl+K** | Scroll the right-hand preview pane down / up |
| **Ctrl+P** | Toggle right-hand file/directory/image preview pane |
| **Esc** | Exit file browser |
| **↑/↓** | Navigate through results |
Image clipboard copying requires `wl-copy` or `xclip`.
### File and Image Previews
<Image src={codePreviewScreenshot} alt="File browser showing a text file and its contents in the preview pane" width={800} />
<Image src={imagePreviewScreenshot} alt="Image scaled into the right-hand preview pane" width={800} />
<Image src={imageDetailsScreenshot} alt="Image preview scrolled down to file details" width={800} />
### Rich Previews
The built-in preview shows plain text, common image formats and directory listings. When `python3` is installed, raffi also runs the previewer it bundles from [`scripts/file-preview`](https://github.com/chmouel/raffi/tree/main/scripts/file-preview), which adds PDF pages, video frames, ebook and album covers, archive listings, syntax-highlighted source, Markdown, JSON and CSV tables. Nothing needs to be installed or configured.
The previewer only needs Python 3. It uses tools such as `bat`, `pdftoppm`, `ffmpegthumbnailer` or `ebook-meta` when they are installed and falls back to plainer output without them; see its README for the full list. Without `python3` on your `PATH`, raffi keeps its plain preview.
<Image src={richPreviewScreenshot} alt="Bundled file previewer showing syntax-highlighted Python from a demo document" width={800} />
<Image src={pdfPreviewScreenshot} alt="A demo PDF's first page rendered in the file browser preview pane" width={800} />
<Image src={filterScreenshot} alt="File browser restricted to files and sorted by modification time, with the current modes in the footer" width={800} />
When you select an entry, raffi shows its plain preview at once and swaps in the previewer's output when it arrives. Results are kept for the session and reused until the file changes.
The previewer follows the raffi theme: it picks the matching `bat` theme (Catppuccin, Nord, Dracula or Gruvbox) or bat's `ansi` theme, which is drawn with the raffi palette, and it ignores your terminal's `BAT_THEME`, `LS_COLORS` and `EZA_COLORS`. To keep a bat theme of your own, set `FILE_PREVIEW_BAT_THEME` in your environment.
Each new selection starts a short `python3` process once you stop moving through the list. To turn rich previews off, for example on a slow machine:
```yaml raffi.yaml
addons:
file_browser:
preview_command: none
```
#### Customising the previewer
The bundled script is a single Python file. To change it, fetch it from the repository, edit your copy and point `preview_command` at it:
```bash
mkdir -p ~/.config/raffi/scripts
curl -fsSL -o ~/.config/raffi/scripts/file-preview.py \
https://raw.githubusercontent.com/chmouel/raffi/main/scripts/file-preview/file-preview.py
chmod +x ~/.config/raffi/scripts/file-preview.py
```
```yaml raffi.yaml
addons:
file_browser:
preview_command: "~/.config/raffi/scripts/file-preview.py"
```
Your copy no longer follows raffi upgrades.
#### Writing your own previewer
Any executable works. Raffi runs the command with `sh -c`, adds the selected path as the last argument, and sets these environment variables:
| Variable | Value |
|---|---|
| `RAFFI_PREVIEW` | `1` |
| `RAFFI_VALUE` | Absolute path of the selected file or directory |
| `RAFFI_PREVIEW_WIDTH`, `RAFFI_PREVIEW_HEIGHT` | Preview pane size in pixels |
| `RAFFI_PREVIEW_COLUMNS`, `RAFFI_PREVIEW_LINES` | Preview pane size in text cells, for tools such as `bat --terminal-width` |
| `RAFFI_THEME`, `RAFFI_THEME_MODE`, `RAFFI_THEME_FG`, ... | The current theme, see [Terminal Colours](../themes/#terminal-colours) |
The path is never pasted into the shell line, so file names containing quotes, spaces or `$(...)` are safe.
The command can print one of two things:
- Text, with ANSI colours and bold, dim, italic or underline styles. The 16 basic colours are drawn with the theme's palette, so output from `bat --theme=ansi`, `eza` or `jq -C` matches the theme. It replaces the built-in preview body. Output is cut after 1000 lines.
- A JSON preview object, in the same format as a [Script Filter preview](../script-filters/#preview-object). Use it to show an image with metadata rows, or several sections. Any `metadata` rows go above raffi's own Path, Size and Modified rows.
```json
{
"badge": "PDF",
"image": {"path": "/home/me/.cache/thumbs/report.png"},
"metadata": [["Pages", "12"], ["Author", "Jane Doe"]]
}
```
JSON is only treated as a preview object when every top-level key is a preview object field (`title`, `subtitle`, `badge`, `icon`, `text`, `image`, `sections`, `metadata`; `refresh` and `dynamic` are accepted and ignored). Anything else, such as a `package.json` printed with `cat`, is shown as text.
If the command prints nothing or exits with a non-zero status, raffi keeps its built-in preview, so a previewer only needs to handle the types it knows. A command that runs longer than 3 seconds is stopped, and raffi shows the error in a `Preview` row.
<Aside type="note">
Terminal image protocols (kitty, sixel, iTerm2) do not work in the preview pane. To show an image, write it to a file and return its path in a JSON preview object.
</Aside>
## Fuzzy Filtering
Text after the last `/` fuzzy-filters the current directory listing:
<Tabs>
<TabItem label="Basic Filter">
```text
/home/us
# Filters /home/ by "us"
# Matches: user, username, usr, etc.
```
</TabItem>
<TabItem label="Deep Filter">
```text
~/Documents/proj
# Filters ~/Documents/ by "proj"
# Matches: projects, my-project, old_projects, etc.
```
</TabItem>
<TabItem label="Extension Filter">
```text
~/Downloads/.pdf
# Filters ~/Downloads/ by ".pdf"
# Shows all PDF files
```
</TabItem>
</Tabs>
## Hidden Files
Control visibility of hidden files (dotfiles):
<Tabs>
<TabItem label="Toggle at Runtime">
Press **Ctrl+H** to toggle hidden file visibility while browsing
</TabItem>
<TabItem label="Default Hidden">
```yaml raffi.yaml
addons:
file_browser:
enabled: true
show_hidden: false
```
</TabItem>
<TabItem label="Default Visible">
```yaml raffi.yaml
addons:
file_browser:
enabled: true
show_hidden: true
```
</TabItem>
</Tabs>
<Aside type="note">
Hidden files start with a dot (`.`), like `.bashrc`, `.config`, etc.
</Aside>
<Image src={hiddenFilesScreenshot} alt="File browser showing hidden project files" width={800} />
## Actions
### Open File
1. Navigate to file
2. Press **Enter**
3. File opens with `xdg-open` (system default application)
```text Example
~/Documents/report.pdf
[Enter] → Opens PDF in default viewer
```
### Navigate Directory
1. Navigate to directory
2. Press **Enter**
3. Directory contents are displayed
```text Example
~/Documents/
[Enter] → Shows contents of Documents/
```
### Go Up a Directory
With the input ending in `/`, press **Backspace** to jump to the parent directory. The directory you came from stays selected, so **Enter** takes you straight back.
```text Example
~/Projects/myapp/src/
[Backspace] → Input becomes: ~/Projects/myapp/ (src/ selected)
```
### Jump Home or to the Root
After a `/`, type `~/` to start over from your home directory, or a second `/` to start over from the root, as in Emacs.
```text Example
~/Projects/myapp/src/~/ → Input becomes: ~/
~/Projects/myapp/src// → Input becomes: /
```
Both shortcuts come from the [`fido_style`](#configuration-options) option, which is on by default.
### Copy Path
1. Navigate to file or directory
2. Press **Ctrl+Enter** (or Ctrl+click the row)
3. Full path copied to clipboard
```text Example
~/Documents/report.pdf
[Ctrl+Enter] → Copies: /home/user/Documents/report.pdf
```
This is the default `secondary_action`; see [Configuration](#configuration) to change it.
### Drag and Drop
Files and directories can be dragged **out of raffi** into any application that accepts drops (file managers, editors, terminals, browsers, email clients...):
1. Press and hold the left mouse button on a file browser row
2. Move the pointer — the drag starts once the pointer moves a few pixels (~8 logical px, typically while still inside the row)
3. Release over the target application to drop
```text Example
~/Documents/report.pdf
[press, move to a file manager] → Drops the file there
```
A quick press and release on a row still activates it like **Enter** would.
The drag offers the file as `text/uri-list` (what file managers expect) and as plain UTF-8 text of the full path (what terminals and most editors take), so text targets that are not drop-aware may still receive the path if they accept text drops.
<Aside type="note">
Dragging out of raffi requires the native Wayland interface (the default). It does not work under XWayland, X11, or in Fuzzel mode.
</Aside>
<Aside type="note">
raffi is a drag source only: it does not accept files dropped **into** it.
</Aside>
### Open in File Manager
Press **Ctrl+B** to open the directory you are browsing in a graphical file manager. With Nautilus, Dolphin, Nemo and Caja the entry selected in raffi is also selected in the file manager; other file managers just open the directory. Raffi picks your desktop's own file manager when it is installed (Dolphin on KDE, Nautilus on GNOME, Thunar on XFCE, Nemo on Cinnamon, Caja on MATE, PCManFM on LXQt/LXDE, and so on). On other sessions such as Hyprland or Sway it uses the first one it finds, and falls back to `xdg-open`. Set [`file_manager`](#configuration) to choose one yourself.
```text Example
~/Projects/myapp/src/
Selected: main.rs
[Ctrl+B] → Opens ~/Projects/myapp/src/ in your file manager with main.rs selected
```
### Autocomplete
1. Navigate to file or directory
2. Press **Tab**
3. Entry is autocompleted into search bar
```text Example
Current: /home/us
Selected: user/
[Tab] → Input becomes: /home/user/
```
## Configuration
Configure the file browser in `raffi.yaml`:
```yaml raffi.yaml
addons:
file_browser:
enabled: true
show_hidden: false
sort: name
sort_reverse: false
show: all
fido_style: true
action: open
secondary_action: copy
file_manager: thunar
```
### Configuration Options
**`enabled`** `boolean` (default: `true`)
Enable or disable the file browser addon
**`show_hidden`** `boolean` (default: `false`)
Show hidden files (dotfiles) by default. Can be toggled at runtime with Ctrl+H.
**`sort`** `string` (default: `name`)
Initial order of the listing. Directories always come before files. Press Ctrl+S to cycle through the modes while browsing; the hint bar shows the current one.
- `name`: alphabetical, ignoring case
- `modified` (or `date`): last modification time, newest first
- `created`: creation time, newest first. Entries on filesystems that do not record it go last.
**`sort_reverse`** `boolean` (default: `false`)
Reverse the order of whichever `sort` mode is active: Z to A for `name`, oldest first for `modified` and `created`. Directories still come first. Ctrl+S does not change this setting.
**`show`** `string` (default: `all`)
Which entries the listing starts with. Press Ctrl+. to cycle through the modes while browsing; the hint bar shows the current one, and Raffi keeps it until it closes.
- `all`: directories and files
- `files`: files only
- `directories` (or `dirs`): directories only
When directories are hidden you can still type a path such as `~/src/` to enter one, and Tab completes the best hidden match when no visible row matches what you typed. Symlinks count as files, so `directories` hides a link to a directory.
**`fido_style`** `boolean` (default: `true`)
Edit paths the way Emacs fido-mode (and ido or vertico) does, so you rarely delete a path one character at a time:
- Backspace on a trailing `/` goes up to the parent directory and selects the one you left (see [Go Up a Directory](#go-up-a-directory)). On `~/` it goes to the parent of your home directory; on `/` it deletes the slash.
- Typing `~/` right after a `/` starts over from your home directory, and a second `/` starts over from the root (see [Jump Home or to the Root](#jump-home-or-to-the-root)).
Set to `false` to edit the path as plain text: Backspace deletes one character and slashes stay as typed.
**`action`** `string` (default: `open`)
What Enter (or a click) does on a file. Enter on a directory always navigates into it. **Ctrl+O** always opens the selected file or directory with `xdg-open`, whatever this is set to. Accepted values:
- `open`: open the file with `xdg-open`
- `copy`: copy the full path to the clipboard
- `insert`: type the full path into the focused app (needs `wtype` or `ydotool`)
- any other string: run it as a shell command, with `{value}` replaced by the full path (also exported as `$RAFFI_VALUE`)
**`secondary_action`** `string` (default: `copy`)
What Ctrl+Enter (or Ctrl+click) does on a file or directory. Takes the same values as `action`.
```yaml raffi.yaml
addons:
file_browser:
action: "code {value}"
secondary_action: insert
```
**`file_manager`** `string` (default: autodetected)
Command used by **Ctrl+B** to open the current directory. The directory is appended as the last argument, or replaces `{value}` if present (it is also exported as `$RAFFI_VALUE`). When the value is just `nautilus`, `dolphin`, `nemo` or `caja` (or a path to one), raffi passes `--select` with the selected entry instead. When unset, raffi detects a file manager as described in [Open in File Manager](#open-in-file-manager).
```yaml raffi.yaml
addons:
file_browser:
file_manager: dolphin
# or a terminal file manager:
# file_manager: kitty yazi
```
**`preview_command`** `string` (default: the bundled previewer when `python3` is installed)
Command that previews the selected entry in the preview pane, replacing the plain preview when it prints something. `none` turns rich previews off. See [Rich Previews](#rich-previews) and [Writing your own previewer](#writing-your-own-previewer) for what it receives and may print. `~` and environment variables are expanded.
```yaml raffi.yaml
addons:
file_browser:
preview_command: "~/.config/raffi/scripts/file-preview.py"
```
### Disable File Browser
```yaml raffi.yaml
addons:
file_browser:
enabled: false
```
## Use Cases
<details>
<summary>Quick File Access</summary>
```text
~/Downloads/
# Type: latest
# Find: latest-report.pdf
# [Enter] to open
```
</details>
<details>
<summary>Copy File Paths</summary>
```text
~/Projects/myapp/src/
# Navigate to: main.rs
# [Ctrl+Enter] to copy path
# Paste into terminal or IDE
```
</details>
<details>
<summary>Browse Config Files</summary>
```text
~/.config/
# [Ctrl+H] to show hidden files
# Navigate to: .bashrc, .vimrc, etc.
# [Enter] to edit
```
</details>
<details>
<summary>Project Navigation</summary>
```text
~/Projects/
# Filter: myapp
# [Enter] to navigate
# Filter: src
# [Tab] to autocomplete
```
</details>
## Visual Indicators
- **Directories** — Listed first in accent color
- **Files** — Listed after directories in normal text
## Requirements
<Aside type="caution">
The file browser requires `xdg-open` to open files (standard on most Linux distributions)
</Aside>
<Aside type="note">
Clipboard operations need `wl-copy` (wl-clipboard), `xclip` or `xsel`
</Aside>
## Examples
### Navigate to Documents
<Steps>
1. **Type Prefix**
Type `~` to start browsing home directory
2. **Filter**
Type `Doc` to filter for Documents
3. **Navigate**
Press **Enter** on Documents folder
4. **Browse Files**
See all files in ~/Documents/
</Steps>
### Open Configuration File
<Steps>
1. **Go to Config**
Type `~/.config/`
2. **Show Hidden**
Press **Ctrl+H** if needed
3. **Filter**
Type filename to filter (e.g., `raf` for raffi)
4. **Open**
Press **Enter** to open with default editor
</Steps>
### Copy Script Path
<Steps>
1. **Navigate**
Type `~/bin/` or `/usr/local/bin/`
2. **Find Script**
Filter by name (e.g., `my-script`)
3. **Copy Path**
Press **Ctrl+Enter** to copy full path
4. **Use Path**
Paste into terminal, config, or documentation
</Steps>
## Tips
<Aside type="tip">
Directories are always listed first and highlighted in the accent color, making it easy to distinguish them from files.
</Aside>
<Aside type="tip">
Use fuzzy filtering after the last `/` to quickly find files: `/home/user/doc` matches `/home/user/Documents/`
</Aside>
<Aside type="tip">
Toggle hidden files with **Ctrl+H** without leaving the file browser.
</Aside>
<Aside type="tip">
Drag files straight out of raffi into another application instead of copying their path first.
</Aside>