0
# Core Framework
1
2
Essential application framework components for building Textual applications, including the main App class, base Widget class, screen management, and decorators for event handling and background tasks.
3
4
## Capabilities
5
6
### Application Class
7
8
The App class is the foundation of every Textual application, managing the event loop, screen stack, styling, and overall application lifecycle.
9
10
```python { .api }
11
class App:
12
"""
13
The main application class.
14
15
Generic type parameter for return value: App[ReturnType]
16
"""
17
def __init__(self, **kwargs):
18
"""
19
Initialize the application.
20
21
Parameters:
22
- css_path: str | list[str] - Path(s) to CSS files for styling
23
- watch_css: bool - Automatically reload CSS files during development
24
"""
25
26
def run(self) -> None:
27
"""Run the application synchronously."""
28
29
async def run_async(self) -> None:
30
"""Run the application asynchronously."""
31
32
def push_screen(self, screen: Screen) -> None:
33
"""
34
Push a new screen onto the screen stack.
35
36
Parameters:
37
- screen: Screen instance to display
38
"""
39
40
def pop_screen(self) -> Screen:
41
"""Pop the current screen from the stack and return it."""
42
43
def exit(self, result=None) -> None:
44
"""
45
Exit the application.
46
47
Parameters:
48
- result: Optional return value for the application
49
"""
50
51
def compose(self) -> ComposeResult:
52
"""Compose the application's default screen widgets."""
53
54
def on_mount(self) -> None:
55
"""Called when the application starts."""
56
57
def on_ready(self) -> None:
58
"""Called when the application is ready to receive events."""
59
60
# Properties
61
screen_stack: list[Screen]
62
title: str
63
sub_title: str
64
css_path: str | list[str] | None
65
```
66
67
### Base Widget Class
68
69
The Widget class is the base for all UI components in Textual, providing composition, rendering, lifecycle management, and event handling capabilities.
70
71
```python { .api }
72
class Widget:
73
"""
74
Base class for all widgets.
75
"""
76
def __init__(self, **kwargs):
77
"""
78
Initialize the widget.
79
80
Parameters:
81
- name: str - Widget name for CSS targeting
82
- id: str - Unique identifier for the widget
83
- classes: str - CSS classes for styling
84
- disabled: bool - Whether the widget is disabled
85
"""
86
87
def compose(self) -> ComposeResult:
88
"""
89
Compose child widgets.
90
91
Returns:
92
Iterator of child widgets
93
"""
94
95
def render(self) -> RenderableType:
96
"""
97
Render the widget content.
98
99
Returns:
100
Rich renderable object
101
"""
102
103
def on_mount(self) -> None:
104
"""Called when widget is added to the DOM."""
105
106
def on_unmount(self) -> None:
107
"""Called when widget is removed from the DOM."""
108
109
def refresh(self, *, repaint: bool = True, layout: bool = False) -> None:
110
"""
111
Refresh the widget.
112
113
Parameters:
114
- repaint: bool - Whether to repaint the widget
115
- layout: bool - Whether to recalculate layout
116
"""
117
118
def remove(self) -> None:
119
"""Remove the widget from its parent."""
120
121
def focus(self, scroll_visible: bool = True) -> None:
122
"""
123
Give focus to the widget.
124
125
Parameters:
126
- scroll_visible: bool - Scroll to make widget visible
127
"""
128
129
def blur(self) -> None:
130
"""Remove focus from the widget."""
131
132
def scroll_to(self, x: int = None, y: int = None, *, animate: bool = True) -> None:
133
"""
134
Scroll to a position.
135
136
Parameters:
137
- x: int - X coordinate to scroll to
138
- y: int - Y coordinate to scroll to
139
- animate: bool - Whether to animate the scroll
140
"""
141
142
# Properties
143
id: str | None
144
name: str | None
145
classes: set[str]
146
disabled: bool
147
parent: Widget | None
148
children: list[Widget]
149
styles: Styles
150
has_focus: bool
151
```
152
153
### Screen Management
154
155
Screen classes represent full-screen views that can be pushed onto a screen stack, enabling complex navigation patterns and modal dialogs.
156
157
```python { .api }
158
class Screen:
159
"""
160
A screen is a special widget that represents the entire terminal.
161
162
Generic type parameter for return value: Screen[ScreenResultType]
163
"""
164
def __init__(self, **kwargs):
165
"""
166
Initialize the screen.
167
168
Parameters:
169
- name: str - Screen name
170
- id: str - Unique identifier
171
- classes: str - CSS classes
172
"""
173
174
def compose(self) -> ComposeResult:
175
"""Compose the screen's widgets."""
176
177
def dismiss(self, result=None) -> None:
178
"""
179
Dismiss the screen with an optional result.
180
181
Parameters:
182
- result: Value to return when screen is dismissed
183
"""
184
185
# Properties
186
title: str
187
sub_title: str
188
auto_focus: str | None
189
190
class ModalScreen(Screen):
191
"""A modal screen that doesn't cover the entire terminal."""
192
pass
193
```
194
195
### Event Handling Decorators
196
197
Decorators for handling events and creating background tasks in Textual applications.
198
199
```python { .api }
200
def on(*selectors, **kwargs):
201
"""
202
Decorator for handling events with CSS selector support.
203
204
Parameters:
205
- *selectors: CSS selectors to match against event targets
206
- **kwargs: Additional event filtering options
207
208
Usage:
209
@on(Button.Pressed, "#my-button")
210
def handle_button(self, event):
211
pass
212
"""
213
214
def work(exclusive: bool = False, thread: bool = False):
215
"""
216
Decorator for creating background tasks.
217
218
Parameters:
219
- exclusive: bool - Whether to cancel other workers when starting
220
- thread: bool - Whether to run in a separate thread
221
222
Usage:
223
@work
224
async def background_task(self):
225
pass
226
"""
227
```
228
229
### Utility Functions and Types
230
231
```python { .api }
232
ComposeResult = Iterator[Widget]
233
"""Type alias for widget composition results."""
234
235
class AwaitMount:
236
"""Awaitable for widget mounting completion."""
237
def __await__(self):
238
"""Wait for widget to be mounted."""
239
240
class MountError(Exception):
241
"""Raised when widget mounting fails."""
242
243
class ScreenStackError(Exception):
244
"""Raised when screen stack operations fail."""
245
```
246
247
## Usage Examples
248
249
### Basic Application Structure
250
251
```python
252
from textual.app import App
253
from textual.widgets import Static
254
from textual.containers import Container
255
256
class MyApp(App):
257
"""A simple Textual application."""
258
259
CSS_PATH = "app.css" # Optional CSS file
260
261
def compose(self):
262
"""Create the UI."""
263
yield Container(
264
Static("Hello World!"),
265
id="main-container"
266
)
267
268
def on_mount(self):
269
"""Set up the application."""
270
self.title = "My Application"
271
self.sub_title = "v1.0.0"
272
273
# Run the application
274
if __name__ == "__main__":
275
MyApp().run()
276
```
277
278
### Screen Navigation
279
280
```python
281
from textual.app import App
282
from textual.screen import Screen
283
from textual.widgets import Button
284
285
class SecondScreen(Screen):
286
"""A secondary screen."""
287
288
def compose(self):
289
yield Button("Go Back", id="back")
290
291
def on_button_pressed(self, event):
292
if event.button.id == "back":
293
self.dismiss("result from second screen")
294
295
class MainApp(App):
296
def compose(self):
297
yield Button("Go to Second Screen", id="goto")
298
299
def on_button_pressed(self, event):
300
if event.button.id == "goto":
301
self.push_screen(SecondScreen())
302
```
303
304
### Event Handling with Decorators
305
306
```python
307
from textual.app import App
308
from textual.widgets import Button, Input
309
from textual import on, work
310
311
class EventApp(App):
312
def compose(self):
313
yield Input(placeholder="Type something...", id="input")
314
yield Button("Process", id="process")
315
316
@on(Button.Pressed, "#process")
317
def handle_process_button(self, event):
318
"""Handle the process button."""
319
input_widget = self.query_one("#input", Input)
320
self.process_text(input_widget.value)
321
322
@work
323
async def process_text(self, text: str):
324
"""Background task to process text."""
325
# Simulate processing
326
await asyncio.sleep(1)
327
self.log(f"Processed: {text}")
328
```