A high-performance, dependency-light TUI (Terminal User Interface) library, supports Bash 3.2+ and BusyBox Ash (with ASH_BASH_COMPAT enabled), with whiptail and dialog style widgets, and more modern, fancier ones too.
Inspired by the dylanaraps philosophy, terminal-menus.sh provides a modern alternative to whiptail and dialog with support for TrueColor and modular layouts.
See the demos :)
Screenshots of each widget are included throughout this document, alongside their descriptions.
The filemanager in fullscreen mode:
The mainmenu in fullscreen mode:
- Bash 3.2+ & BusyBox Ash: Works on old, modern & embedded systems (Mac and Linux).
- Minimal Dependencies: Requires only
ash/bashandbusybox(coreutils applets).gitandsudoare optional and feature-gated. - TrueColor (24-bit): Customisable RGB themes.
- Many Layouts: Modal popups, full-screen UIs, toast notifications, and command palettes.
- High Performance: Pre-computed lowercase caches, viewport file reading (no
sedper row),find-based directory listing (no shell glob ARG_MAX), shell parameter expansion overawk/cut/trforks, andMAX_FILTER_ITEMSsafety cap. BusyBox applets are auto-detected and preferred when available.
Shell requirements: The library requires
[[ ]],read -n, and$'...'support.
Bash 3.2+ works natively. BusyBox Ash needsASH_BASH_COMPATenabled at build time.
The library checks these on startup and exits with a clear error if any are missing.
Simply source the script:
. ./terminal-menus.sh # Portable (ash, bash)
source ./terminal-menus.sh # Bash-specificThe included demo script (terminal-menus-demo.sh) exercises every widget. Three ways to use it:
./terminal-menus-demo.sh # Interactive widget picker menu
./terminal-menus-demo.sh all # Run all 24 demos sequentially
./terminal-menus-demo.sh filemanager # Run one widget demo and exitValid widget names: infobox, msgbox, yesno, inputbox, passwordbox, menu, checklist, radiolist, filtermenu, gauge, textbox, tailbox, tree, configtree, form, filepicker, table, filtertable, filemanager, spreadsheet, kanban, mainmenu, texteditor.
When run with no arguments, the script shows a filtermenu listing all widgets. Select "All widgets" to run everything in order, or pick individual widgets to run one at a time (returns to the picker after each).
Displays a standard modal with an OK button.
Environment Variables:
OK_LABEL— Custom OK button text (default:"OK")BACKTITLE— Background title textTUI_MODE— Layout mode (centered, fullscreen, classic, popup, top, bottom, toast, palette)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Enter — Confirm / Close
OK_LABEL="Let's Go!"
msgbox "Welcome" "This is a standard message box.\nEnjoy!"A non-blocking message window without buttons. Ideal for background tasks.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout mode
infobox "Processing" "I'm an infobox.\nI show messages without buttons."
sleep 2Standard boolean choice. Includes support for default focus (1 for Yes, 2 for No).
Environment Variables:
YES_LABEL— Custom Yes button text (default:"YES")NO_LABEL— Custom No button text (default:"NO")BACKTITLE— Background title textTUI_MODE— Layout modeTUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Left / Right — Switch focus between Yes/No
- Enter — Confirm selection
if yesno "Question" "Do you want to continue?" 2; then
echo "User chose Yes"
fiCaptures a single line of text from the user.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_RESULT— Empty string on cancelTUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Left / Right — Move cursor within input
- Backspace — Delete character before cursor
- Enter — Confirm input
- Esc — Cancel (returns empty, sets
TUI_RESULT='')
USER_NAME=$(inputbox "Identity" "Enter your username:" "foo")Masked input for sensitive tokens or passwords.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_RESULT— Empty string on cancelTUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Enter — Confirm input
- Esc — Cancel (returns empty, sets
TUI_RESULT='')
PASS=$(passwordbox "Security" "Enter a secret token:" "ppp")A standard single-choice selection list. Also see filtermenu.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or k / j — Navigate
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Enter — Select highlighted item
- q — Cancel / Quit
CHOICE=$(menu "Simple Menu" "Pick a fruit:" 2 "Apple" "Banana" "Cherry")For large item sets, use --file to read items from a file (avoids ARG_MAX):
CHOICE=$(menu "Menu" "Pick one:" --file /path/to/items.txt)Multiple-choice selection list. Returns each selected item on a new line.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or k / j — Navigate
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Space — Toggle selection for current item
- Enter — Confirm and return all selected items
- q — Cancel / Quit
CHKS=$(checklist "Checklist" "Select multiple options:" 2 "Option 1" "Option 2" "Option 3")For large item sets, use --file to read items from a file (avoids ARG_MAX):
CHKS=$(checklist "Checklist" "Select:" --file /path/to/items.txt)Mutually exclusive selection list.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or k / j — Navigate
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Space — Select current item
- Enter — Confirm selection
- q — Cancel / Quit
RADIO=$(radiolist "Radiolist" "Choose exactly one:" 2 "Low" "Medium" "High")For large item sets, use --file to read items from a file (avoids ARG_MAX):
RADIO=$(radiolist "Radiolist" "Choose:" --file /path/to/items.txt)A searchable, real-time filtered list for large datasets.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Type — Filter list in real-time
- Up / Down or w / s or k / j — Navigate filtered results
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Tab — Toggle focus (list / filter)
- Left / Right — Move cursor within filter input
- / — Focus filter input (from list)
- Backspace — Delete last filter character; when empty, focuses filter
- Enter — Select highlighted item
- q — Cancel / Quit (when not in filter input)
COUNTRIES="Argentina\nAustralia\nBrazil\nCanada"
SEARCH=$(filtermenu "Search" "Type to filter:" 1 "$COUNTRIES")Visual progress bar tracking piped input (0-100).
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
( for i in {0..100..20}; do echo $i; sleep 0.3; done ) | gauge "Deploying" "Working..."A read-only scrollable file viewer.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or j / k — Scroll vertically
- Page Up / Page Down or J / K or [ / ] — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Enter — Close viewer
textbox "Source view" "File: terminal-menus.sh" "./terminal-menus.sh"Live-monitoring of a file (similar to tail -f).
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Enter — Close viewer
tailbox "Log Monitor" "File: server.log" "server.log"Deep hierarchical navigation. Returns the full path from root of the selected node. Optional search/filter input.
Environment Variables:
ENABLE_FILTER— Set totrueto show a search/filter input (default:false)BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or k / j — Navigate tree
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Left / Right or a / d or h / l — Collapse / Expand nodes
- Enter — Select node (returns full path from root)
- Space — Toggle selection (config mode only)
- / — Focus filter input (when
ENABLE_FILTER=true) - Tab — Toggle focus between filter and tree (when
ENABLE_FILTER=true) - q — Quit
TREE_DATA=("0|usr|/usr|true" "1|bin|bin/|true" "2|bash|bash|false")
TREE_RES=$(ENABLE_FILTER=true tree "Browser" "Select path:" 1 "${TREE_DATA[@]}")For large tree data, use --file to read nodes from a file (one node per line, avoids ARG_MAX):
TREE_RES=$(ENABLE_FILTER=true tree "Browser" "Select path:" --file /path/to/nodes.txt)Hierarchical configuration toggle. Returns a list of variable assignments. Optional search/filter input. Children of unchecked parents are automatically excluded.
Environment Variables:
ENABLE_FILTER— Set totrueto show a search/filter input (default:false)BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or k / j — Navigate tree
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Left / Right or a / d or h / l — Collapse / Expand nodes
- Space — Toggle checkbox value
- Enter — Confirm and return variable assignments
- / — Focus filter input (when
ENABLE_FILTER=true) - Tab — Toggle focus between filter and tree (when
ENABLE_FILTER=true)
CONFIG_OUT=$(ENABLE_FILTER=true configtree "Settings" "Configure System" 1 "${CONFIG_DATA[@]}")For large tree data, use --file to read nodes from a file (avoids ARG_MAX):
CONFIG_OUT=$(ENABLE_FILTER=true configtree "Settings" "Configure System" --file /path/to/nodes.txt)Advanced form builder. Returns shell-evaluable assignments.
Field Types:
> Label:var=default— Text input>* Label:var=default— Password input (masked)[ ] Label:var— Checkbox, use[x]for checked( ) Label:var— Radio, use(*)for selected{ } display1:val1,=default:val2,...— Dropdown menu (=marks default)---— Visual separator
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Tab — Cycle through interactive fields
- Up / Down — Navigate between fields
- Left / Right — Move cursor in text/password inputs
- Space — Toggle checkbox/radio, open/close dropdown
- Enter — Submit form
- q — Cancel / Quit
- Esc — Close dropdown or cancel
Dropdown Specifics:
- When a dropdown is open, Up / Down navigates options
- Space selects the highlighted option and closes the dropdown
- Option values are extracted from the last
:indisplay:value
FORM_OUT=$(form "Provisioning" "Node" \
"> User:user=guest" \
">* Password:password" \
"Country:" \
"{ } United Kingdom:uk,=USA:usa,South Africa:southafrica" \
"[x] Wifi:wlan0" \
"(*) Prod:prod")
eval "$FORM_OUT"A lightweight file and directory picker, supports picking single or multiple items. Also see filemanager.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_CD_FILE— File path to writecd "dir"commands to (for external shell integration)TUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or k / j / w / s — Navigate
- Enter or Right or l / d — Open directory / Select file
- Left or h / a — Go to parent directory
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Tab — Toggle mark on current item (for multiple selection)
- . — Toggle hidden files
- q — Cancel / Exit
FILE_PICK=$(filepicker "File picker" "Choose a file" "." 2)Navigable table from CSV. Returns the command or text in the last (hidden) column of the selected row.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Up / Down or w / s or k / j — Scroll rows
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Enter — Select row (returns last column value)
- q — Cancel / Quit
RESULT_CMD=$(table "Action Center" "Pick an item" "data.csv" 1)Filterable table from CSV. Returns the command or text in the last (hidden) column of the selected row.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Type — Filter rows in real-time
- Up / Down or w / s or k / j — Scroll filtered results
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Tab — Toggle focus (list / filter)
- Left / Right — Move cursor in filter
- / — Focus filter input (from list)
- Enter — Select row (returns last column value)
- Backspace — Delete last filter character; when empty, focuses filter
- q — Cancel / Quit (when not in filter input)
- Esc — Cancel / Exit
RESULT_CMD=$(filtertable "Service Search" "Type to search, pick an item." "services.csv" 1)A fast, full-featured file manager, with search & filter, file previews, multiple select, command prompts, and more.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_CD_FILE— File path to writecd "dir"commands to (for external shell integration)TUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
[Arrows] Navigate (also w/a/s/d and h/j/k/l)
[ENTER] Open / Select
[TAB] Toggle add to selection (sel/{})
[SPACE] Toggle current selection
[.] Toggle hidden files
[,] Toggle detailed list
[i] Toggle ignored (.gitignore)
[/] Search filter
[:/!] Shell prompt (! for root)
[sel/{}] Current selection in prompt
[e] Edit file in $EDITOR
[f/F] New file (f) or folder (F)
[r] Rename item
[x/c/v] Cut/copy/paste
[PgUp] / [PgDn] Scroll by page (also [J]/[K])
[Home] / [End] Jump to top / bottom (also [g]/[G])
[~] Go home
[?] Show help
[[]/[]] Preview scroll up/down
[q/ESC] Exit / Cancel
Notes:
- TAB selections persist across view toggles (
,), directory changes, and cross-directory navigation. Select files in one directory, navigate to another, and TAB-select more — all selections are returned on exit. - Tab highlights selected items in yellow. Selected items remain highlighted when switching between normal and detailed list views.
Usage:
filemanager "Home" "$HOME"You can highlight multiple items using Tab, and hit : to launch a command prompt (! for root prompt), and then run rm {} or rm sel to delete the selected files.
TUI_CD_FILE integration — Use filemanager as a "cd on exit" directory picker:
export TUI_CD_FILE=/tmp/tui_cd.txt
filemanager "Browse" "$HOME"
if [ -f "$TUI_CD_FILE" ]; then
cd "$(cat "$TUI_CD_FILE")"
fiAn Excel-like sheet, supports formulas (SUM|AVG|MIN|MAX|COUNT|COUNTA|ROUND|CONCAT|IF), horizontal/vertical scrolling, and undo/redo.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Arrows or w / a / s / d or h / j / k / l — Navigate cells
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to first / last cell
- Enter — Enter edit mode for current cell
- Right / Left — Move cursor in edit mode
- ? — Toggle help popup (lists all expressions)
- q — Quit
FINAL_DATA=$(spreadsheet "budget.csv")A multi-column kanban board, with a searchable table view.
Environment Variables:
BACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Arrows or w / a / s / d — Navigate
- Page Up / Page Down — Scroll by page
- Home / End — Jump to top / bottom
- W / A / S / D or H / J / K / L — Move item
- / — Search items
- o — Cycle sort (by rank, modified, created, completed)
- O — Toggle ascending / descending
- Enter or e — Edit note in
$EDITOR - n — New note
- t — Append tag
- z — Undo
- Z — Redo
- q — Quit
kanban "Awesome Project" "Manage notes & tickets" ./some-folderA sidebar menu on the left, where each menu item loads a navigable table, which can launch commands and other widgets.
Environment Variables:
TUI_PERSISTENT_FILTERS— Set totrueto retain filter text when switching sidebar itemsBACKTITLE— Background title textTUI_MODE— Layout modeTUI_HIDE_FOOTER— Set totrueto hide the controls footer bar (adds 2 extra content rows)TUI_EXTRA_KEYS— Custom keybindings (see Custom Keybindings)
Controls:
- Tab — Toggle focus between sidebar and table
- Up / Down or w / s or k / j — Navigate sidebar or table
- Left / Right — Switch focus to sidebar / table
- Page Up / Page Down or J / K — Scroll by page
- Home / End or g / G — Jump to top / bottom
- Enter — Select item, or run command from selected table row
- / — Focus filter input (when in table view)
- Backspace — Focus filter input
- 1-9 — Sort table by column N (press same key again to toggle asc/desc)
- q — Quit (when focus is on sidebar or table; types
qif in filter input)
mainmenu "Media Center" "Select category" "$MENU_CFG" 1A full-featured terminal text editor with selection, clipboard, undo/redo, search & replace, horizontal scroll, auto-indent, and more.
Environment Variables:
BACKTITLE— Background title text (shows file path)TUI_MODE— Layout modeTA_SEPARATORS— Characters that act as word separators for Ctrl+Left/Right navigation (default:-/ _+.,:;!?()[]{}<>@#$%^&*~'\"|\\)TUI_HIDE_FOOTER— Set totrueto hide the controls footer bar
Controls:
Arrows Move cursor
Shift+Arrows Select text
Shift+Home/End Select to line start/end
Ctrl+Arrows Word left/right
Ctrl+Shift+Arrow Select word
Home/End Line start/end
Ctrl+Home/End File top/bottom
PgUp/PgDn Page scroll
Enter New line (with auto-indent)
Backspace/Del Delete
Ctrl+Del Delete word right
Ctrl+W Delete word left
Tab 4-space indent
Ctrl+A Select all
Ctrl+X/C/V Cut/Copy/Paste
Ctrl+Z/Y Undo/Redo
Ctrl+D Duplicate line/selection
Ctrl+K Delete line
Ctrl+L Select line
Alt+Up/Down Move line up/down
Ctrl+F Find (search term input, highlights matches)
Ctrl+G Find next match (wraps around)
Ctrl+R Find & Replace (form with two fields)
Ctrl+O Open file via filepicker
Ctrl+S Save
Ctrl+Q Quit (prompts if unsaved)
F1 Help (scrollable modal with full controls list)
Usage:
# Open an existing file for editing
texteditor "notes.txt"
# Start with an empty buffer (returns content to stdout)
RESULT=$(texteditor)The library uses a global TUI_MODE variable to determine the geometry and placement of widgets.
You can change this on the fly between widget calls to create dynamic interfaces.
centered(Default): A balanced box (74x22) centered on the screen.fullscreen: Occupies the entire terminal area. Best forfilemanagerandmainmenu.classic: A standard 80x25 terminal box centered for a nostalgic feel.popup: A small (50x7) high-focus modal for quick alerts or single inputs.
top: A full-width bar (10 rows high) at the very top of the terminal.bottom: A full-width bar (10 rows high) snapped to the bottom edge.
toast: A slim notification box (35x4) snapped to the top-right corner.palette: A versatile "Command Palette" that uses theANCHORvariable for placement.
When using palette, set the ANCHOR environment variable to a two-letter code:
tl/tr: Top-Left / Top-Rightbl/br: Bottom-Left / Bottom-Righttc/bc: Top-Center / Bottom-Centercc: Dead Center
A standard centered question:
TUI_MODE="centered" yesno "Title" "Do you want to proceed?"A quick notification toast that disappears after 3 seconds:
TUI_MODE="toast" infobox "System" "Backup completed successfully." && sleep 3A command palette anchored to the bottom-right:
TUI_MODE="palette" ANCHOR="br" menu "Actions" "Rebuild" "Deploy" "Quit"A full-screen dashboard:
TUI_MODE="fullscreen" BACKTITLE="Server Monitor" mainmenu "Dashboard" "Select Tool" "$MENU_CFG"The library uses a set of global variables for its TrueColor (24-bit RGB) palette. You can change these at any time to create custom themes or dark/light mode toggles.
BG_MAIN: The main background of the widget window.BG_WIDGET: The background for buttons, list items, and inputs.BG_ACTIVE: The primary focus/highlight colour (Deep Blue by default).FG_TEXT: The primary text colour.FG_HINT: Dimmed text for footer controls and shortcuts.BG_INPUT: Near-black background for text input fields.
BG_MODAL: Override the dimmed modal background (default:"50;50;50").
To change the theme on the fly, update the variables and then call _init_tui. This is useful for "Settings" menus that apply changes immediately without restarting the script.
# Define a 'Midnight' theme
set_midnight_theme() {
BG_MAIN="10;20;30" # Very dark blue
BG_WIDGET="30;40;50" # Muted blue-grey
HL_BLUE="0;255;255" # Cyan selection
# Reload the TUI engine to apply changes
_init_tui
}
# Example: Change theme based on user choice
if yesno "Theme Switcher" "Switch to Midnight mode?"; then
set_midnight_theme
fiThe variable HL_BLUE is an alias for BG_ACTIVE. When you update one, the library automatically re-calculates the bold and inverted ANSI sequences during the next _init_tui call, ensuring all widgets (menus, checklists, etc.) stay visually consistent.
A key feature of this library is the ability to launch Modal Widgets on top of a "parent" fullscreen widget (like mainmenu or filemanager). This creates a layered, "desktop-like" experience without losing the state of the background application.
To achieve this, use the modal wrapper. This automatically handles background dimming, state preservation, and terminal cleanup.
The modal function tells the library to "faint" the background and treat the next widget as a temporary overlay.
# Inside a script or a CSV command:
modal "yesno 'Playback' 'Resume from last seen?'"This is most powerful when used in the Command column of your table or mainmenu CSVs:
Item,Category,Command
Settings,System,modal "form 'Settings' 'Edit User' '> User:u'"
Delete,Action,modal "yesno 'Confirm' 'Are you sure?'" && rm file.tmpAdd custom keyboard shortcuts to any interactive widget. Bind a key to arbitrary shell code — typically a modal call — to overlay popups without leaving the current widget.
Format: one key=command per line in the env var.
| Key syntax | Example | Effect |
|---|---|---|
| Literal char | ?=modal "infobox 'Help' '...'" |
Triggers on ? |
ctrl_<c> |
ctrl_x=modal "yesno 'Quit?' '...'" |
Control+X |
shift_<c> |
shift_u=modal "msgbox '…'" |
Uppercase U |
Controls:
- Keys are checked before the widget's native handler, so you can shadow built-in keys.
- The value is any shell code (typically
modal "widget 'title' 'body'"). - Control codes use
_separator:ctrl_c,ctrl_x, etc. - Single quotes inside values are automatically escaped; avoid unescaped double quotes in message text.
Example — filemanager with help, info, and about modals:
export TUI_EXTRA_KEYS="
shift_u=modal \"msgbox 'Help' 'Navigate with arrows/j/k.\nTab to select.\nq to quit.'\"
2=modal \"infobox 'System Info' 'terminal-menus.sh v1.0'\"
3=modal \"msgbox 'About TUI_EXTRA_KEYS' 'Set TUI_EXTRA_KEYS env var with:\n key=command\n ctrl_x=command'\"
"
filemanager "Browse" "$HOME"Works in all 17 interactive widgets: menu, checklist, radiolist, msgbox, yesno, inputbox, passwordbox, textbox, tailbox, form, spreadsheet, filtermenu, filepicker, tree/configtree, table/filtertable, mainmenu, filemanager, kanban, texteditor.
The mainmenu demo includes a update_config helper to manage key=value configuration files with automatic duplicate removal:
# Saves 'theme=dark' to your config file
update_config "theme='dark'"| Variable | Widget | Purpose |
|---|---|---|
TUI_HIDE_FOOTER=true |
All scrollable widgets | Hide the controls footer bar and add 2 extra lines to the scrollable content area |
TUI_PERSISTENT_FILTERS=true |
mainmenu |
Keep filter text when switching sidebar items |
ENABLE_FILTER=true |
tree, configtree |
Enable search/filter input |
TREE_RETURN_VALUES=true |
tree |
Return label paths instead of ID paths |
TUI_CD_FILE |
filepicker, filemanager |
Write cd commands to a file for shell integration |
TUI_MODE |
All | Layout mode (centered, fullscreen, classic, popup, top, bottom, toast, palette) |
TUI_WIDTH / TUI_HEIGHT |
custom mode |
Custom widget dimensions |
TUI_X / TUI_Y |
custom mode |
Custom widget position |
BACKTITLE |
All | Background title text |
OK_LABEL |
msgbox |
OK button label |
YES_LABEL / NO_LABEL |
yesno |
Yes/No button labels |
TUI_EXTRA_KEYS |
All interactive widgets | Custom keybindings (see Custom Keybindings) |
MAX_FILTER_ITEMS |
mainmenu, filtermenu, filtertable, tree, configtree |
Max items to process in filter loops (default: 5000). Prevents freezes with 10K+ items |
BG_MODAL |
modal wrapper |
Modal overlay background colour |
ANCHOR |
palette mode |
Anchor position (tl, tr, bl, br, tc, bc, cc) |
Tests live in test/. Four types available:
./test/test_shell_compat.shChecks syntax (ash -n, bash -n) on both scripts, runs the pty form test under each shell, and executes all widget integration tests.
Widget integration tests use ash by default. To run under a specific shell:
cd test && python3 -m unittest test_demo_widgets
cd test && SHELL=bash python3 -m unittest test_demo_widgets
cd test && SHELL=ash python3 -m unittest test_demo_widgetsRun all 181 tests across 24 widgets:
cd test && python3 -m unittest test_demo_widgets -vRun a single widget's tests:
python3 -m unittest test.test_demo_widgets.TestMenu
python3 -m unittest test.test_demo_widgets.TestForm.test_full_flowWidgets covered: menu, checklist, radiolist, msgbox, yesno, inputbox, passwordbox, textbox, tailbox, form, infobox, gauge, spreadsheet, filtermenu, filepicker, tree, configtree, table, filtertable, filemanager, mainmenu, kanban, modal, extra_keys, texteditor.
python3 test/test_form_pty.shValidates form widget output — 7 assertions on checkbox states, radio selection, dropdown default, and password field. To run under a specific shell:
SHELL=ash python3 test/test_form_pty.sh
SHELL=bash python3 test/test_form_pty.shAll commands run from the project root:
# Form visual test — opens form, submits with Enter, captures 2 screenshots
cd test && ash interactive_runner.sh wrappers/form_test.sh drivers/form_test.driver
# Mainmenu visual test — Tab/Enter modal flow, types text, submits, quits (4 screenshots)
cd test && ash interactive_runner.sh wrappers/mainmenu_test.sh drivers/mainmenu_test.driver
# Full 24-widget demo — automates all widgets in terminal-menus-demo.sh (~24 screenshots)
cd test && ash interactive_runner.sh wrappers/full_demo_wrapper.sh test_full_demo.shScreenshots are written to /tmp/tui_tests/<timestamp>/.
The project ships with a GitHub Actions workflow (.github/workflows/test.yml) that runs
syntax checks, form pty test, and all widget integration tests on every push/PR.
| Path | Purpose |
|---|---|
test/testlib.py |
PtyRunner, TuiTestCase, KEY constants — shared PTY test framework |
test/test_demo_widgets.py |
Python integration test module covering all 24 widgets (181 tests) |
test/wrappers/ |
Shell wrappers that source the library and invoke each widget |
test/interactive_runner.sh |
Harness: starts Xvfb, launches xterm, sources driver, sends keystrokes |
test/test_shell_compat.sh |
Shell compatibility test runner — ash + bash syntax and pty functional |
test/test_form_pty.sh |
Python pty-based form output test (supports SHELL=ash / SHELL=bash) |
test/test_full_demo.sh |
Keystroke driver for the full 24-widget demo |
test/drivers/ |
Keystroke command scripts sourced by the harness |
Copyright (c) 2026 sc0ttj
Licensed under the MIT License:
https://opensource.org






















