Skip to main content

Crate photon_ui

Crate photon_ui 

Source
Expand description

§photon-ui

A blazing fast, minimal terminal UI framework for Rust.

Photon UI is a lightweight, high-performance TUI library built on crossterm. It features a custom differential renderer that only redraws what changed, ANSI-aware text wrapping, OSC 8 hyperlink support, terminal image rendering (Kitty and iTerm2 protocols), a Cassowary constraint-based layout engine, and a component-based architecture.

§Features

  • Differential renderer — Only updates cells that changed between frames, minimizing terminal output and improving performance.
  • Component-based architecture — Build UIs by composing simple, reusable Component trait implementations.
  • Built-in components — 27 components including text, input, editor, buttons, tables, trees, sidebars, tabs, modals, panels, progress bars, markdown, and image widgets.
  • Constraint-based layout — Split terminal space using the Cassowary solver via Layout, Constraint, and Rect.
  • Dual editing modes — Both Emacs and vim keybindings for Input and Editor components, switchable at runtime.
  • Terminal image support — Render images inline using the Kitty graphics protocol or iTerm2 inline images.
  • ANSI-aware text handling — Properly measures and wraps text containing ANSI escape sequences, Unicode, and grapheme clusters.
  • Overlays and modals — Position floating content with Anchor-based constraints and modal dialogs that capture input.
  • Focus management — The TUI runtime handles focus cycling and routes input events to the focused component.
  • Zero unnecessary dependencies — Core functionality relies only on crossterm, unicode-width, unicode-segmentation, pulldown-cmark, base64, thiserror, and kasuari.

§Quick start

Add photon-ui to your Cargo.toml:

[dependencies]
photon-ui = "0.1"

Build a simple app:

use photon_ui::{Component, TUI, TestTerminal};
use photon_ui::components::Text;

let mut tui = TUI::new(Box::new(TestTerminal::new(80, 24)));
tui.mount(Box::new(Text::new("Hello, world!", 0, 0)));
tui.render_frame().unwrap();

For a real application, use ProcessTerminal to drive the actual terminal:

use photon_ui::{TUI, Event};
use photon_ui::terminal::{ProcessTerminal, Terminal};
use photon_ui::components::{Text, Input};
use std::time::Duration;

fn main() -> std::io::Result<()> {
    let mut term = ProcessTerminal::new();
    term.start()?;

    let mut tui = TUI::new(Box::new(term));
    tui.mount(Box::new(Text::new("Name:", 0, 0)));
    tui.mount(Box::new(Input::new()));

    loop {
        tui.render_frame()?;

        if crossterm::event::poll(Duration::from_millis(100))? {
            let event = match crossterm::event::read()? {
                crossterm::event::Event::Key(key) => Event::Key(key),
                crossterm::event::Event::Resize(w, h) => Event::Resize(w, h),
                other => continue,
            };
            tui.handle_input(&event);
        }
    }
}

§Components

ComponentDescription
TextStatic text with optional horizontal and vertical padding.
TruncatedTextText that truncates with an ellipsis when wider than the container.
BoxA container with configurable vertical padding and optional background styling.
SpacerEmpty vertical space.
InputSingle-line text input with Emacs and vim modes, kill-ring, and undo.
EditorMulti-line text editor with Emacs and vim modes, kill-ring, and undo.
SelectListScrollable list with keyboard navigation and selection.
SettingsListToggle list for boolean settings.
LoaderAnimated spinner with optional colored message.
CancellableLoaderSpinner that can be cancelled via Ctrl+C.
MarkdownRenders CommonMark markdown (headings, bold, italic, inline code, lists).
ImageWidgetDisplays images inline via Kitty or iTerm2 graphics protocols.
ButtonClickable button with primary, ghost, cream, text, and dark variants.
BreadcrumbsHierarchical breadcrumb navigation trail.
ContainerGeneric container for composing child components.
DivLayout container that splits space among children with borders and padding.
DividerHorizontal or vertical divider line, optionally with a label.
HeaderPage header with title and right-aligned actions.
ModalModal dialog overlay with title, border, and focus capture.
PanelPanel container with optional rounded, thin, thick, or double borders.
ProgressBarProgress bar with optional label and percentage display.
SidebarSidebar navigation with icons and keyboard selection.
StatusBarStatus bar with left, center, and right segments.
TableTable with sortable columns, row selection, and keyboard navigation.
TabsTab bar with keyboard navigation between tabs.
TreeViewCollapsible tree view with expand/collapse and keyboard navigation.

§Architecture

§Component trait

Every visible element implements the Component trait:

pub trait Component {
    fn render(&self, width: u16) -> Result<Rendered, RenderError>;
    fn render_rect(&self, rect: Rect) -> Result<Rendered, RenderError>;
    fn handle_input(&mut self, event: &Event) -> InputResult;
    fn wants_key_release(&self) -> bool;
    fn as_focusable(&self) -> Option<&dyn Focusable>;
    fn as_focusable_mut(&mut self) -> Option<&mut dyn Focusable>;
}
  • render produces the lines of text (and optional cursor or image commands) for the current frame.
  • render_rect renders into a specific rectangular area, used by layout-aware components.
  • handle_input receives events when the component has focus.
  • Focusable components participate in the tab order managed by TUI.

§Renderer

The Renderer tracks the previous frame and computes a minimal set of cursor movements and writes needed to update the terminal. This avoids clearing the screen or redrawing unchanged content. It automatically selects one of three strategies:

  • FirstRender — outputs all lines (assumes a clean alternate screen).
  • FullRedraw — clears the screen and redraws everything (used on resize).
  • Diff — computes the first and last changed line and only rewrites that region.

§Layout engine

The layout system uses the kasuari Cassowary constraint solver. A Layout splits a Rect into sub-rects based on Constraint values (Length, Min, Max, Percentage, Ratio, Fill) with configurable Direction, Flex, Margin, and Spacing.

use photon_ui::layout::{Constraint, Direction, Rect};
use photon_ui::layout::layout::Layout;

let layout = Layout::vertical([
    Constraint::Length(3),   // header
    Constraint::Min(10),     // main content
    Constraint::Length(1),   // status bar
]);
let areas = layout.split(Rect::new(0, 0, 80, 24));

§TUI runtime

TUI owns the terminal backend, manages a stack of components, handles focus cycling (Tab / Shift+Tab), and supports overlays positioned with Anchor and OverlayConstraints. Modal dialogs capture all input until dismissed with Esc.

§Input modes

Both Input and Editor support Emacs and vim editing styles:

EmacsVimAction
Ctrl+A0 or ^Move to start of line
Ctrl+E$Move to end of line
Ctrl+KDKill to end of line
Ctrl+YpYank (paste)
Ctrl+WdawKill word
Ctrl+F / Ctrl+Bl / hMove forward / backward
i / EscEnter / exit insert mode

Enable vim mode at construction time or toggle it at runtime with set_vim_mode_enabled.

§Running the demo

The included demo showcases every component across multiple pages:

cargo run --example demo

Controls:

KeyAction
15Switch demo page
Tab / Shift+TabCycle focus
q or Ctrl+CQuit

Re-exports§

pub use events::Event;
pub use events::Key;
pub use events::Modifiers;
pub use events::matches_key;
pub use keybindings::KeybindingsManager;
pub use keybindings::default_bindings;
pub use renderer::InputResult;
pub use renderer::RenderError;
pub use renderer::RenderStrategy;
pub use renderer::Rendered;
pub use renderer::Renderer;
pub use terminal::Terminal;
pub use terminal::TestTerminal;
pub use tui::Anchor;
pub use tui::Overlay;
pub use tui::OverlayConstraints;
pub use tui::OverlayPosition;
pub use tui::TUI;

Modules§

autocomplete
Fuzzy autocomplete engine.
components
UI components (text, input, editor, table, etc.). UI components provided by photon-ui.
events
Event abstraction over crossterm.
fuzzy
Fuzzy matching logic.
image
Terminal image protocol encoding.
keybindings
Keybindings manager and default action maps.
kill_ring
Clipboard / kill-ring for editors.
layout
Constraint-based layout engine. Constraint-based layout engine.
renderer
Differential terminal renderer.
terminal
Terminal trait and test double.
theme
Beam Design Language theme system. The Beam Design Language theme system for photon-ui.
tui
TUI runtime and focus management.
undo_stack
Undo / redo stacks.
utils
ANSI-aware text wrapping and width measurement.
word_navigation
Word-boundary navigation helpers.

Structs§

KeyEvent
Represents a key event.

Traits§

Component
A UI element that can be rendered and respond to input.
Focusable
Extension of Component for elements that can receive keyboard focus.