Terminal UI

You can build a text-based interface that will run in the terminal using Dioxus.

Hello World screenshot

Note: this book was written with HTML-based platforms in mind. You might be able to follow along with TUI, but you'll have to adapt a bit.


TUI support is currently quite experimental. But, if you're willing to venture into the realm of the unknown, this guide will get you started.

  • It uses flexbox for the layout
  • It only supports a subset of the attributes and elements
  • Regular widgets will not work in the tui render, but the tui renderer has its own widget components that start with a capital letter. See the widgets example
  • 1px is one character line height. Your regular CSS px does not translate
  • If your app panics, your terminal is wrecked. This will be fixed eventually

Getting Set up

Start by making a new package and adding Dioxus and the TUI renderer as dependencies.

cargo new --bin demo
cd demo
cargo add dioxus
cargo add dioxus-tui

Then, edit your main.rs with the basic template.

// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
use dioxus::prelude::*;

fn main() {
    // launch the app in the terminal

// create a component that renders a div with the text "Hello, world!"
fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            "Hello, world!"

To run our app:

cargo run

Press "ctrl-c" to close the app. To switch from "ctrl-c" to just "q" to quit you can launch the app with a configuration to disable the default quit and use the root TuiContext to quit on your own.

// todo remove deprecated
#![allow(non_snake_case, deprecated)]

use dioxus::events::{KeyCode, KeyboardEvent};
use dioxus::prelude::*;
use dioxus_tui::TuiContext;

fn main() {
            // Some older terminals only support 16 colors or ANSI colors
            // If your terminal is one of these, change this to BaseColors or ANSI

fn App(cx: Scope) -> Element {
    let tui_ctx: TuiContext = cx.consume_context().unwrap();

    cx.render(rsx! {
        div {
            width: "100%",
            height: "10px",
            background_color: "red",
            justify_content: "center",
            align_items: "center",
            onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.key_code {

            "Hello world!"

Hot Reload

  1. Hot reloading allows much faster iteration times inside of rsx calls by interpreting them and streaming the edits.
  2. It is useful when changing the styling/layout of a program, but will not help with changing the logic of a program.


Install dioxus-cli.


  1. Run:
dx serve --hot-reload --platform desktop
  1. Change some code within a rsx or render macro
  2. Save and watch the style change without recompiling


  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.