ScriptsApr 14, 2026·3 min read

Textual — Rapid Application Development Framework for the Terminal

Textual is a Python framework for building sophisticated TUI applications with CSS-based styling, async event handling, and 20+ built-in widgets. The same app can run in the terminal or in a web browser.

TL;DR
Textual builds sophisticated terminal UIs in Python with CSS styling, async events, and browser deployment.
§01

What it is

Textual is a Python framework for building terminal user interfaces (TUIs) with CSS-based styling, async event handling, and over 20 built-in widgets. Built on top of Rich, Textual lets you create applications that run both in the terminal and in a web browser through Textual Web.

Textual is for Python developers who want to build interactive command-line applications with modern UI patterns -- data tables, tree views, tabs, modals, and forms -- without leaving the terminal.

§02

How it saves time or tokens

Building interactive terminal UIs with curses or blessed requires managing screen buffers, input handling, and rendering manually. Textual provides a component model similar to web frameworks: you compose widgets, style them with CSS, and handle events with async callbacks.

The CSS styling system means you can iterate on appearance without changing Python code. Change colors, spacing, and layout by editing a .tcss file, and the app updates live with textual-dev.

§03

How to use

  1. Install Textual and the dev tools:
pip install textual textual-dev
  1. Create a basic app:
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Button

class HelloApp(App):
    CSS = 'Button { margin: 1; }'

    def compose(self) -> ComposeResult:
        yield Header()
        yield Button('Click me', id='hi')
        yield Footer()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.notify('Button clicked')

if __name__ == '__main__':
    HelloApp().run()
  1. Run with live CSS reloading:
textual run --dev my_app.py
§04

Example

A data table with sortable columns:

from textual.app import App, ComposeResult
from textual.widgets import DataTable

class TableApp(App):
    def compose(self) -> ComposeResult:
        yield DataTable()

    def on_mount(self) -> None:
        table = self.query_one(DataTable)
        table.add_columns('Name', 'Language', 'Stars')
        table.add_rows([
            ('Textual', 'Python', '25000'),
            ('Rich', 'Python', '49000'),
            ('Charm', 'Go', '15000'),
        ])

if __name__ == '__main__':
    TableApp().run()

This renders a sortable, scrollable table in the terminal with keyboard navigation.

§05

Related on TokRepo

§06

Common pitfalls

  • Textual's CSS is not standard web CSS. It supports a subset of properties with terminal-specific additions like dock, layer, and offset. Check the Textual CSS reference for supported properties.
  • Async event handling means you need to understand Python's asyncio. Long-running synchronous code in event handlers blocks the UI. Use run_worker() for background tasks.
  • Terminal capabilities vary. Textual works best in modern terminals (iTerm2, Windows Terminal, Kitty). Older terminals may not render all widgets correctly.

Frequently Asked Questions

Can Textual apps run in a web browser?+

Yes. Textual Web serves your TUI app as a web application. The same Python code renders in a browser without any frontend JavaScript. This is useful for sharing tools with non-technical users who may not have a terminal setup.

How does Textual relate to Rich?+

Textual is built on top of Rich. Rich handles text rendering, tables, and formatting. Textual adds the application framework: widgets, layout, event handling, and CSS styling. You can use Rich objects inside Textual widgets.

What widgets does Textual include?+

Textual ships with over 20 widgets including Button, Input, Select, DataTable, Tree, ListView, Tabs, TextArea, ProgressBar, Switch, Checkbox, RadioButton, Header, Footer, and more. You can also create custom widgets by subclassing Widget.

Does Textual support mouse input?+

Yes. Textual handles mouse clicks, scrolling, and hover events in terminals that support mouse reporting. Buttons are clickable, tables are scrollable, and drag interactions are possible with custom handlers.

Can I test Textual apps?+

Yes. Textual provides a testing framework with pilot objects that simulate user input. You can programmatically click buttons, type text, and assert on widget state in pytest tests without rendering to a real terminal.

Citations (3)

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets