Textual
A modern framework for building TUI applications in Python. It adopts CSS, DOM, and reactive programming models, bringing web development concepts to the terminal environment.
GitHub Overview
Textualize/textual
The lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.
Topics
Star History
Framework
Textual
Overview
Textual is an innovative framework for building modern TUI (Text-based User Interface) applications in Python. It brings web development concepts (CSS, DOM, reactive programming) to the terminal environment, enabling intuitive and high-performance TUI application development.
Details
Textual was developed by Textualize in 2021, providing a new paradigm for Python TUI development. Unlike traditional curses-based approaches, it adopts modern web development best practices.
Key Features
- CSS-like Styling: Customize application appearance with CSS-like syntax
- DOM Structure: Manage UI hierarchy with HTML-like DOM (Document Object Model)
- Reactive Attributes: Automatic UI updates when data changes
- Rich Widget Set: Diverse built-in widgets including buttons, inputs, tables, trees
- Event-Driven: Message-based event system
- Animations: Smooth animation effects
- Theme System: Customizable themes and color schemes
- Web Deployment: Terminal apps can also run in web browsers
Architecture
Textual's architecture consists of the following main components:
- App: Application entry point
- Screen: Special Widget representing the entire screen
- Widget: Base class for UI elements
- MessagePump: Foundation for event processing
- Compositor: Rendering system
- CSS Engine: Styling engine
Pros and Cons
Pros
- Leverage modern web development knowledge
- High-performance rendering and animations
- Rich documentation and community support
- Cross-platform support (Linux, macOS, Windows)
- Can run in web browsers
- Rich set of built-in widgets
- Intuitive CSS-like styling
- Powerful development tools (debug console, live reload, etc.)
Cons
- Limited learning resources as a relatively new framework
- Limited track record for large-scale applications
- Dependency on Rich library
- May be feature-heavy for lightweight applications
Key Links
Code Example
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import Button, Header, Footer, Static
class CounterApp(App):
\"\"\"A simple counter app.\"\"\"
CSS_PATH = "counter.tcss"
def __init__(self):
super().__init__()
self.counter = 0
def compose(self) -> ComposeResult:
\"\"\"Create child widgets for the app.\"\"\"
yield Header()
yield Footer()
yield Container(
Static(f"Count: {self.counter}", id="counter"),
Button("Increment", id="increment"),
Button("Decrement", id="decrement"),
id="app-grid",
)
def on_button_pressed(self, event: Button.Pressed) -> None:
\"\"\"Event handler called when a button is pressed.\"\"\"
if event.button.id == "increment":
self.counter += 1
elif event.button.id == "decrement":
self.counter -= 1
# Update the counter display
counter_widget = self.query_one("#counter", Static)
counter_widget.update(f"Count: {self.counter}")
if __name__ == "__main__":
app = CounterApp()
app.run()
CSS file (counter.tcss):
#app-grid {
display: grid;
grid-size: 1 3;
grid-rows: 1fr;
margin: 1 2;
min-height: 0;
}
#counter {
content-align: center middle;
text-style: bold;
}
Button {
margin: 1 2;
}