selectui
A terminal UI for selecting and searching through items with a clean, split-pane interface.
Features
- Search Bar: Filter items in real-time as you type
- Split View:
- Left pane: List of items showing title and subtitle
- Right pane: Detailed view of selected item (all keys/values)
- Fuzzy Search: Toggle with
fkey for flexible matching - Case Sensitivity: Toggle with
ikey for exact case matching - Readline Controls: Support for common shortcuts (^A, ^E, ^W, ^U)
- Status Bar: Shows total entries, matched entries, and active flags
- Help: Press
?to see keybindings - Oneshot Mode: Use
-oflag to exit after first selection
Installation
This project uses uv for dependency management.
cd selectui
uv sync
Or install as a library:
pip install -e .
Usage
As a CLI Tool
The script reads JSON objects line-by-line from stdin (JSONL format). Each line should be a valid JSON object with at least a title key (and optionally a subtitle key). Items are loaded asynchronously, so the UI updates as new objects arrive.
Basic usage:
cat example.jsonl | uv run selectui
Oneshot mode (exit after selection):
cat example.jsonl | uv run selectui --oneshot
or
cat example.jsonl | uv run selectui -o
Example with jq:
# Select from a list of files (convert to JSONL)
find . -type f | while read f; do echo "{\"title\": \"$f\"}"; done | uv run selectui
# Or using jq to output JSONL (one object per line)
cat data.json | jq -c '.[]' | uv run selectui
Streaming example:
# Simulate streaming data - items appear one by one
for i in 1 2 3 4 5; do echo "{\"title\": \"Item $i\", \"subtitle\": \"Description $i\"}"; sleep 0.5; done | uv run selectui
Custom title/subtitle keys:
# Use 'name' as title and 'description' as subtitle
cat data.jsonl | uv run selectui -t name -s description
# Use 'filename' as title, no subtitle
cat files.jsonl | uv run selectui --title filename
As a Library
SelectUI can be used as a library in your Python applications:
from selectui import SelectUI
items = [
{"title": "Python", "subtitle": "High-level language"},
{"title": "Rust", "subtitle": "Systems language"},
{"title": "Go", "subtitle": "Concurrent language"},
]
app = SelectUI(items=items, oneshot=True)
app.run()
if app.selected_item:
print(f"You selected: {app.selected_item['title']}")
With Pydantic Models (Type Safety)
from selectui import SelectUI, SelectItem
# Type-safe items with validation
items = [
SelectItem(title="Python", subtitle="High-level language", info="1991"),
SelectItem(title="Rust", subtitle="Systems language", info="2010"),
]
app = SelectUI(items=items, oneshot=True)
app.run()
Converting from JSON with Custom Keys
from selectui import SelectItem
# Convert JSON/dict with custom field mappings
data = {"name": "Alice", "role": "Engineer", "team": "Backend"}
item = SelectItem.from_dict(data, title_key="name", subtitle_key="role", info_key="team")
See the examples/ directory for more library usage examples:
- examples/minimal.py - Simplest possible usage
- examples/simple_library_example.py - Common patterns
- examples/library_usage.py - Comprehensive feature demonstrations
- examples/pydantic_example.py - Pydantic models with type safety
- examples/json_conversion.py - JSON conversion with custom keys
For detailed library documentation, see examples/README.md.
Keybindings
Navigation
↑/↓- Move selection up/down (works from search bar!)PgUp/PgDn- Page up/down (works from search bar!)j/k- Vim-style navigation (when list is focused)Enter- Select item and output to stdoutEsc,q, or^C- Quit
Search
- Type to filter items
^A- Move cursor to start of line^E- Move cursor to end of line^W- Delete word backward^U- Clear search lineBackspace- Delete character←/→- Move cursor left/right in search box
Toggles
f- Toggle fuzzy search (shows "F" in status bar when active)i- Toggle case-sensitive search (shows "I" in status bar when active)
Input Format
The input should be JSONL (JSON Lines) - one JSON value per line. Each line can be either: - A single JSON object - A JSON array of objects (all items will be added to the list)
{"title": "Item 1", "subtitle": "Description of item 1"}
{"title": "Item 2", "subtitle": "Description of item 2"}
[{"title": "Item 3"}, {"title": "Item 4"}]
title: Displayed as the main text (configurable with-t/--title)subtitle: Displayed below the title (configurable with-s/--subtitle)- Other keys: All keys and values are shown in the detail pane
The UI loads items asynchronously as they arrive, showing a "..." indicator in the status bar while streaming is in progress.
Command Line Options
| Option | Description |
|---|---|
-o, --oneshot |
Exit after first selection |
-t, --title KEY |
Key to use for item title (default: title) |
-s, --subtitle KEY |
Key to use for item subtitle (default: subtitle) |
-i, --info KEY |
Key to display as right-aligned info in each entry |
-e, --events |
Enable events mode (see below) |
Events Mode
When --events is enabled, pressing CTRL+key combinations will emit a JSONL event to stdout containing the pressed key and the currently selected item:
cat items.jsonl | selectui --events
Output format when CTRL+x is pressed:
{"key":"ctrl+x","item":{"title":"Selected Item","subtitle":"..."}}
This allows building interactive workflows where different CTRL keys trigger different actions on the selected item. Reserved keys (like CTRL+C for quit) are not emitted.
Output
When an item is selected (by pressing Enter), the complete JSON object is output to stdout. In non-oneshot mode, the UI continues running after output. In oneshot mode, the program exits after the first selection.
Example
See example.jsonl for a sample data file with job listings.
cat example.jsonl | uv run selectui
Dependencies
- Python 3.8+
- textual (for the TUI framework)
- thefuzz (for fuzzy searching)
License
MIT
