Creating a UI for your Python scripts can be a pain, especially if you just need something one step up from a CLI interface. It seems waste to have to configure a whole web app or GUI sometimes.
Enter Textual, a Python suite that allows you to quickly (like, a couple of minutes tops) spin up beautiful text-based UIs, even running over the web!
What is it?
Textual
is a modern Python framework for building TUI (Text User Interface) apps using asyncio
and rich
for styling.
Here by way of example is my To-Do app:
Even the debug traces are made pretty!:
Getting Started
Make sure you have Python 3.7 or newer.
pip3 install textual
Optionally, install rich
to experiment with more styling:
pip3 install rich
Create a file called hello_textual.py
:
from textual.app import App
from textual.widgets import Static
class HelloTextual(App):
def compose(self):
yield Static("Hello, Textual!")
if __name__ == "__main__":
HelloTextual().run()
How it works:
App
is the base class for your application.compose()
is a generator where you define what widgets to display.Static
is a simple widget that shows fixed text.
Adding Style
Textual uses CSS-like styling. Create a file hello_textual.tcss
:
Screen {
background: black;
color: green;
align: center middle;
}
Then update your app to include this stylesheet:
from textual.app import App
from textual.widgets import Static
class HelloTextual(App):
CSS_PATH = "hello_textual.tcss"
def compose(self):
yield Static("Hello, Textual!")
if __name__ == "__main__":
HelloTextual().run()
Buttons and Labels
We want our apps to be interactive so the obvious next step is to add a button that when clicked does something.
Create a file called button_example.py
:
from textual.app import App, ComposeResult
from textual.widgets import Label, Button
from textual.containers import Vertical
class HelloWorldApp(App):
def compose(self) -> ComposeResult:
with Vertical():
self.label = Label("Press the button")
yield self.label
yield Button("Click Me", id="hello-button")
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "hello-button":
self.label.update("Hello, world!")
if __name__ == "__main__":
HelloWorldApp().run()
How it works:
Label
displays text and can be updated dynamically.Button
triggers events you can respond to.on_button_pressed
is triggered when a button is clicked.Vertical()
is a layout container to stack widgets vertically.
If, like me, you are using an IDE that does not like Ctrl-Q to quit out of the application, you can add the following lines right under the class definition like so:
# Class definition, new lines go right under ..
class HelloWorldApp(App):
# Add these lines
"""A simple Textual app to demonstrate the basics."""
BINDINGS = [("q", "quit", "Quit"),]
Now you will be able to quit out with q
Next Steps
Now that you've created a basic app with styles, you can explore more widgets such as Input
and DataTable
You can also handle user input and add interactivity by overriding methods like:
on_mount
on_key
on_button_pressed
For more info, check out the official docs:
https://textual.textualize.io/
This is just the beginning. Textual gives you the ability to build all sorts of apps with tons of widgets, structured layouts, mouse support, and themes.