Build a Textual TUI App Skeleton in Python

Create a minimal Textual terminal UI app with a header, label, button, and footer, ready for interactive mock demonstrations.

Easy Python 3.10+ Aug 9, 2026 Modern tooling 14 views 0 copies

Requires third-party packages — install first
pip install textual

Python code

22 lines
Python 3.10+
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Button, Label

class MockApp(App):
    """A minimal Textual TUI app skeleton."""

    BINDINGS = [("q", "quit", "Quit")]

    def compose(self) -> ComposeResult:
        """Create child widgets."""
        yield Header()
        yield Label("Welcome to the mock app!")
        yield Button("Press Me", id="press")
        yield Footer()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button clicks by updating the label."""
        label = self.query_one(Label)
        label.update(f"Button clicked!")

if __name__ == "__main__":
    MockApp().run()

Output

stdout
Interactive terminal app. Displays header, 'Welcome to the mock app!', a 'Press Me' button (renders as a clickable box), and footer. Pressing 'q' or clicking the button quits or updates the label to 'Button clicked!'. Key presses show in the footer: 'q → Quit'.

How it works

The app defines a compose method that yields widgets in order: Header, Label, Button, and Footer. Textual's event system dispatches Button.Pressed to the matching on_button_pressed handler, where query_one(Label) finds the widget to update. The BINDINGS list registers the 'q' key to quit the app with a help hint in the footer. Running the app enters an event loop that renders the TUI and processes input until quit.

Common mistakes

  • Importing from `textual.widget` instead of `textual.widgets`.
  • Forgetting to call `await` on widget updates when using async handlers.
  • Overriding `on_load`, `on_mount`, or `compose` incorrectly and shadowing built-in behavior.
  • Not specifying `id` on widgets when using `query_one` with a type; it may match multiple instances.

Variations

  1. Run the app in test mode using `App.run_test()` for headless testing of widget interactions.
  2. Use `app.push_screen()` to switch between multiple screen layouts in a multi-page TUI.

Real-world use cases

  • Build CLI configuration tools where users navigate and edit settings with keyboard and mouse.
  • Create a lightweight data-entry form for internal ops dashboards that runs over SSH.
  • Prototype a terminal-based log viewer with filters before hooking into a real log stream.

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Modern tooling

Related tutorials and quizzes for this topic.