DEV Community

changelogHW
changelogHW

Posted on

I Tried Textual for a Weekend. Here's Why I'm Not Going Back to Plain CLI Output

I've been writing Python CLI tools for years the same way: print() statements, maybe some argparse, and if I was feeling fancy, rich for colored output. Then I actually sat down and built something with Textual, and it changed how I think about terminal apps.

If you haven't heard of it, Textual is a Python framework (from the same team behind rich) for building full TUI (Terminal User Interface) apps --- think dashboards, forms, file browsers, all running inside your terminal, but with actual layout, widgets, mouse support, and CSS-like styling.

Why I picked it up

I wanted a quick internal tool to monitor some background jobs --- nothing worth a full web dashboard, but plain log output wasn't cutting it either. Textual felt like the middle ground I didn't know I needed.

So instead of just reading docs, I built something real with it: a command-logging utility --- a TUI where you can log commands you run (with context/notes attached) without breaking flow to open a separate notes app. Code's on GitHub.

Setting it up

pip install textual textual-dev
Enter fullscreen mode Exit fullscreen mode

That's it. No extra system dependencies, no weird terminal config. textual-dev gives you a live console for debugging, which honestly saved me a lot of guesswork and the devtools lets you serve an app launched directly from a Python file.

The part that surprised me: CSS

Yes, actual CSS. You style widgets with .tcss files:

Screen {
    background: $surface;
}

#sidebar {
    width: 30;
    border: solid green;
}
Enter fullscreen mode Exit fullscreen mode

Coming from years of manually padding strings to "layout" a CLI, this felt like cheating. Widgets snap into place, you get flexbox-like sizing, and you're not fighting with \n and spaces to align things.

A minimal example

from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Static

class DemoApp(App):
    CSS_PATH = "demo.tcss"

    def compose(self) -> ComposeResult:
        yield Header()
        yield Static("Hello from Textual", id="body")
        yield Footer()

if __name__ == "__main__":
    DemoApp().run()
Enter fullscreen mode Exit fullscreen mode

Run it, and you already get a header, footer with keybindings, and a styled body. No boilerplate hell.

What actually impressed me

  • Reactive attributes : change a variable, and the UI updates automatically. No manual redraw logic.
  • Built-in widgets : DataTable, Tree, ListView, Input, all ready to use. I didn't have to build a table renderer from scratch.
  • Works over SSH : since it's still a terminal app, no port forwarding or browser needed. That alone makes it worth it for remote/server tooling.
  • Hot reload : textual run --dev app.py and CSS changes reflect instantly without restarting.

Where it got tricky

  • Debugging layout issues (widgets not sizing how you expect) took some trial and error — the docs help, but you'll spend time in the CSS live-reload loop.
  • Testing TUI apps isn't as straightforward as testing a normal script; Textual has a test harness (Pilot), but it's a different mental model.
  • Quitting the application (Ctrl+q) is sometimes tricky due to some similar key bindings.

The project: a command-logging utility

The idea was simple; I run a lot of one-off commands (debugging, ops, random scripts) and kept losing track of why I ran them. So I built a small Textual app that lets you:

  • Log a command + a quick note in one input
  • Browse past entries in a scrollable list
  • Delete entries without leaving the terminal

Nothing groundbreaking, but it's exactly the kind of tool that's annoying to build with plain print() and perfect for Textual's widget set: Input for capture, and reactive state to keep the list in sync as you add entries.

Should you use it?

If you're building anything more than a script that prints and exits — a monitoring tool, an admin utility, a game --- Textual is worth the few hours it takes to get comfortable. It's actively maintained, the community's responsive, and it makes terminal apps feel like a legitimate UI surface instead of an afterthought.

Terminal Screenshot of Textual Serve devtool

Note: I'm not affiliated with Rich/Textual in any way and these are my personal opinions.

Top comments (0)