Skip to content
ALL PROJECTS

...MAIN PROJECT... / 04

r-modals

Active

Native modals for Rust, without building a GUI.

ROLE
Creator & maintainer
YEAR
2026
STATUS
Active
LANGUAGE
Rust
RusteframeeguiX11Wayland

...OVERVIEW...

What it is

Every script eventually needs to ask a question. A shell script wants a picker; a Rust tool wants a confirm box; a window manager binding wants a launcher. r-modals turns that into one blocking call: Modal::new("Title").run() returns the pick, or None when you cancel.

Under the hood it is eframe/egui, so the window is native, borderless and fast on both X11 and Wayland. You do not need to learn an immediate-mode GUI to use it.

A picker that does more than pick

  • 01

    Options with labels, descriptions and icons

    Icons can be a file path, raw bytes, or RGBA data.

  • 02

    Submenus

    Drill down with sub_option instead of flattening every choice into one list.

  • 03

    Actions

    Run a command, a shell one-liner, or a Rust closure when an option is selected.

  • 04

    Search

    Substring or fuzzy matching across label, id, description and keywords. Multi-select, empty states, custom input and MRU history are opt-in.

The parts that make it feel native

Confirm and Prompt dialogs return bool and Option<String> with the same styling and keyboard behavior. Workspaces can place a dialog on a specific Hyprland, Sway, i3, niri, KDE or generic X11 workspace — and optionally do it without stealing focus.

A spawnable dialog API lets a program start itself as a child dialog and stream options in. That is how shell scripts get the same contract through --menu, --ask, --confirm and --error. Themes are plain CSS, not a bespoke styling layer: Theme::dark(), Theme::light(), Theme::transparent_dark() and Theme::auto() cover the common cases.

Shortcuts and prefixes

One config.toml can bind keys to options or terminal commands, and bind the start of a query to an action. Prefixes complete with Tab while you type: >s completes to >sync, >sh to >show items. If the query does not start a registered prefix, Tab completes the focused row's label instead.

Shortcut keys are consumed before the built-in keys, so you can rebind Enter if you really want to. Option shortcuts render as row hints automatically.

Command-line mode

Piping stdin to r-modals --menu turns it into a dmenu replacement. The pick goes to stdout and the exit code says what happened: 0 for a pick, 1 for cancel, 2 for an error. That small contract is what makes it usable from shell scripts without a wrapper.