What is rtui?
rtui lets you build full-screen terminal user interfaces (TUIs) from R. It wraps Python’s Textual framework via reticulate, giving you access to 35+ widgets, 12 chart types, CSS-like styling, reactive state, screens, timers, key bindings, a command palette, and 10 built-in colour themes – all without writing a single line of Python.
Terminal only: rtui apps require a real terminal emulator (Windows Terminal, iTerm2, Terminal.app, or any xterm-compatible terminal). They will not work in the RStudio console, R GUI, Jupyter notebooks, or any embedded R console. Always save your code as a
.Rfile and run it withRscript.
Installation
Step 1: Install the R package
# From GitHub
install.packages("remotes")
remotes::install_github("orijitghosh/rtui")
# Or from a local checkout
# remotes::install_local("path/to/rtui")Step 2: Install Python dependencies
rtui needs Python >= 3.10 with the textual and
textual-plotext packages. A one-time setup function handles
everything:
rtui::install_python_deps()This creates a virtualenv called r-rtui and installs the
required Python packages into it.
Restart R after installation, then verify the setup:
rtui::rtui_doctor()Windows-specific setup
On Windows, avoid using the Microsoft Store version of Python. Instead, use a standard Python install from python.org, and pass its full path if reticulate discovers the wrong interpreter:
rtui::install_python_deps(
python = "C:/Users/you/AppData/Local/Programs/Python/Python312/python.exe"
)
rtui::rtui_doctor()Your first app
The fastest way to get started is quick_app(), which
builds and runs an app in a single call:
Run this from a real terminal:
You should see a full-screen app with “Hello from rtui!” centred on
screen. Press Ctrl+C to exit.
One-liner data viewer
Want to explore a data frame interactively? One line:
data_viewer(mtcars)This opens a full-screen sortable data table. Click column headers to
sort. Press q to quit.
A counter app
Let’s build something interactive – a counter with increment, decrement, and reset buttons:
library(rtui)
quick_app(
title = "Counter",
layout = vstack(
header(),
center(middle(vstack(
digits("0", id = "count"),
hstack(
button("-1", id = "dec"),
button("+1", id = "inc"),
button("Reset", id = "reset")
)
))),
footer()
),
on_click = list(
inc = function(event, state) {
n <- state$get("n", 0L) + 1L
state$set("n", n)
update(state$app, "count", value = as.character(n))
state
},
dec = function(event, state) {
n <- state$get("n", 0L) - 1L
state$set("n", n)
update(state$app, "count", value = as.character(n))
state
},
reset = function(event, state) {
state$set("n", 0L)
update(state$app, "count", value = "0")
state
}
),
bindings = list(
binding("q", "quit_app", "Quit", priority = TRUE)
),
on_action = function(event, state) {
if (event$value == "quit_app") return(quit())
state
}
)What’s happening here?
Layout:
vstack()stacks children vertically. Inside we usecenter()andmiddle()to centre the content.digits()shows large-format numbers, andbutton()creates clickable buttons.Event handling:
on_clickis a named list mapping widget ids to handler functions. Each handler receivesevent(with click details) andstate(mutable key-value store). Handlers must returnstate.Updating widgets:
update(state$app, "count", value = "5")changes the digits widget’s display. Every widget can be updated by id.Key bindings:
binding("q", "quit_app", "Quit")maps theqkey to an action called"quit_app". Theon_actionhandler checksevent$valueand callsquit()to exit.
The two-step pattern: tui_app() + run()
quick_app() is a convenience wrapper. For more control,
use tui_app() to create the app object, then call
$run():
app <- tui_app(
title = "My App",
layout = vstack(
header(),
text("Built with tui_app()", id = "msg"),
footer()
),
on_key = function(event, state) {
if (event$key == "q") return(quit())
state
}
)
# Inspect before running
print(app)
# Run it
app$run()This is useful when you want to inspect or modify the app object before launching.
Running apps (terminal only!)
TUI apps take over the entire terminal screen. They will not work in:
- RStudio (neither the console nor the terminal pane)
- R GUI (Rgui.exe on Windows, R.app on macOS)
- Jupyter notebooks
- Emacs ESS / VS Code R console or any other embedded R console
You must save your code as a .R file and run it from a
real terminal emulator:
On Windows, this assumes Rscript is on
PATH. If PowerShell cannot find it, add R’s
bin directory to PATH or reinstall R with
command-line tools available.
Dark and light mode
Apps default to dark mode. Toggle at creation or at runtime:
# Start in light mode
quick_app(title = "Light", dark = FALSE, layout = ...)
# Toggle at runtime from a handler
on_action = function(event, state) {
if (event$value == "toggle_dark") dark_toggle(state$app)
state
}Applying a theme
rtui ships with 10 colour themes. Pass one to the css
parameter:
quick_app(
title = "Themed App",
layout = vstack(header(), text("Dracula theme!"), footer()),
css = tui_theme("dracula")
)Available themes: dracula, nord,
monokai, solarized_dark,
solarized_light, gruvbox,
catppuccin, ocean, forest,
sunset.
List them all:
Notifications
Show transient notification toasts from any handler:
notify(state$app, "File saved!", severity = "info")
notify(state$app, "Disk full!", severity = "error")Severity levels: "info", "warning",
"error".
What’s next?
Now that you have the basics, explore these guides:
- Layouts and Widgets: All containers and widgets with examples
- State, Events, and Reactivity: Deep dive into handlers, state management, and reactive bindings
- Charts and Data Visualisation: Terminal charts and ggplot2 rendering
- Advanced Features: Screens, timers, key bindings, command palette, forms, and workers
- Example Gallery: 15 runnable example apps with progressive complexity
