or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

content.mdcore-framework.mdevents.mdindex.mdstyling.mdtesting.mdwidgets.md

widgets.mddocs/

0

# Widget Library

1

2

Complete collection of built-in UI components for creating rich terminal interfaces, including input controls, display widgets, navigation components, data widgets, and utility components.

3

4

## Capabilities

5

6

### Input and Form Controls

7

8

Interactive widgets for user input and form creation.

9

10

```python { .api }

11

class Button(Widget):

12

"""A clickable button widget."""

13

14

class Pressed(Message):

15

"""Sent when the button is pressed."""

16

def __init__(self, button: Button): ...

17

18

def __init__(

19

self,

20

label: RenderableType = "",

21

*,

22

variant: str = "default",

23

disabled: bool = False,

24

**kwargs

25

):

26

"""

27

Initialize a button.

28

29

Parameters:

30

- label: Button text or renderable content

31

- variant: Button style ("default", "primary", "success", "warning", "error")

32

- disabled: Whether the button is disabled

33

"""

34

35

def press(self) -> None:

36

"""Programmatically press the button."""

37

38

class Input(Widget):

39

"""Single-line text input widget."""

40

41

class Changed(Message):

42

"""Sent when input value changes."""

43

def __init__(self, input: Input, value: str): ...

44

45

class Submitted(Message):

46

"""Sent when input is submitted (Enter key)."""

47

def __init__(self, input: Input, value: str): ...

48

49

def __init__(

50

self,

51

value: str = "",

52

placeholder: str = "",

53

*,

54

password: bool = False,

55

restrict: str | None = None,

56

type: str = "text",

57

max_length: int = 0,

58

**kwargs

59

):

60

"""

61

Initialize an input widget.

62

63

Parameters:

64

- value: Initial input value

65

- placeholder: Placeholder text when empty

66

- password: Whether to hide input characters

67

- restrict: Regex pattern to restrict input

68

- type: Input type ("text", "integer", "number")

69

- max_length: Maximum input length (0 for unlimited)

70

"""

71

72

# Properties

73

value: str

74

placeholder: str

75

cursor_position: int

76

77

class TextArea(Widget):

78

"""Multi-line text editor with syntax highlighting."""

79

80

class Changed(Message):

81

"""Sent when text content changes."""

82

83

def __init__(

84

self,

85

text: str = "",

86

*,

87

language: str | None = None,

88

theme: str = "monokai",

89

soft_wrap: bool = True,

90

tab_size: int = 4,

91

**kwargs

92

):

93

"""

94

Initialize a text area.

95

96

Parameters:

97

- text: Initial text content

98

- language: Programming language for syntax highlighting

99

- theme: Color theme for highlighting

100

- soft_wrap: Whether to wrap long lines

101

- tab_size: Number of spaces per tab

102

"""

103

104

def load_text(self, text: str) -> None:

105

"""Load new text content."""

106

107

# Properties

108

text: str

109

cursor_position: tuple[int, int]

110

111

class Checkbox(Widget):

112

"""Boolean checkbox input."""

113

114

class Changed(Message):

115

"""Sent when checkbox state changes."""

116

def __init__(self, checkbox: Checkbox, value: bool): ...

117

118

def __init__(self, label: str = "", *, value: bool = False, **kwargs):

119

"""

120

Initialize a checkbox.

121

122

Parameters:

123

- label: Checkbox label text

124

- value: Initial checked state

125

"""

126

127

def toggle(self) -> None:

128

"""Toggle the checkbox state."""

129

130

# Properties

131

value: bool

132

133

class Switch(Widget):

134

"""Toggle switch control."""

135

136

class Changed(Message):

137

"""Sent when switch state changes."""

138

139

def __init__(self, *, value: bool = False, **kwargs):

140

"""

141

Initialize a switch.

142

143

Parameters:

144

- value: Initial switch state

145

"""

146

147

def toggle(self) -> None:

148

"""Toggle the switch state."""

149

150

# Properties

151

value: bool

152

153

class RadioButton(Widget):

154

"""Individual radio button."""

155

156

class Changed(Message):

157

"""Sent when radio button selection changes."""

158

159

def __init__(self, label: str = "", *, value: bool = False, **kwargs):

160

"""

161

Initialize a radio button.

162

163

Parameters:

164

- label: Radio button label

165

- value: Whether this button is selected

166

"""

167

168

# Properties

169

value: bool

170

171

class RadioSet(Widget):

172

"""Group of radio buttons."""

173

174

class Changed(Message):

175

"""Sent when selection changes."""

176

def __init__(self, radio_set: RadioSet, pressed: RadioButton): ...

177

178

def __init__(self, *labels: str, **kwargs):

179

"""

180

Initialize a radio set.

181

182

Parameters:

183

- *labels: Radio button labels

184

"""

185

186

# Properties

187

pressed_button: RadioButton | None

188

pressed_index: int

189

190

class Select(Widget):

191

"""Dropdown selection widget."""

192

193

class Changed(Message):

194

"""Sent when selection changes."""

195

196

def __init__(

197

self,

198

options: Iterable[tuple[str, Any]] | Iterable[str],

199

*,

200

value: Any = None,

201

allow_blank: bool = True,

202

**kwargs

203

):

204

"""

205

Initialize a select widget.

206

207

Parameters:

208

- options: Selection options as (label, value) tuples or strings

209

- value: Initial selected value

210

- allow_blank: Whether to allow no selection

211

"""

212

213

# Properties

214

value: Any

215

options: list[tuple[str, Any]]

216

```

217

218

### Display and Content Widgets

219

220

Widgets for displaying static and dynamic content.

221

222

```python { .api }

223

class Static(Widget):

224

"""Display static rich content."""

225

226

def __init__(self, renderable: RenderableType = "", **kwargs):

227

"""

228

Initialize a static widget.

229

230

Parameters:

231

- renderable: Content to display (string, Rich object, etc.)

232

"""

233

234

def update(self, renderable: RenderableType) -> None:

235

"""Update the displayed content."""

236

237

class Label(Widget):

238

"""Simple text label."""

239

240

def __init__(self, text: str = "", **kwargs):

241

"""

242

Initialize a label.

243

244

Parameters:

245

- text: Label text content

246

"""

247

248

# Properties

249

text: str

250

251

class Pretty(Widget):

252

"""Pretty-printed Python objects using Rich."""

253

254

def __init__(self, obj: Any, **kwargs):

255

"""

256

Initialize a pretty widget.

257

258

Parameters:

259

- obj: Python object to pretty-print

260

"""

261

262

def update(self, obj: Any) -> None:

263

"""Update the displayed object."""

264

265

class Markdown(Widget):

266

"""Markdown content renderer."""

267

268

class LinkClicked(Message):

269

"""Sent when a markdown link is clicked."""

270

271

def __init__(self, markdown: str = "", **kwargs):

272

"""

273

Initialize a markdown widget.

274

275

Parameters:

276

- markdown: Markdown text content

277

"""

278

279

# Properties

280

markdown: str

281

282

class MarkdownViewer(Widget):

283

"""Scrollable markdown viewer with navigation."""

284

285

def __init__(self, markdown: str = "", **kwargs):

286

"""

287

Initialize a markdown viewer.

288

289

Parameters:

290

- markdown: Markdown content to display

291

"""

292

293

def go(self, location: str) -> None:

294

"""Navigate to a specific location in the document."""

295

296

class RichLog(Widget):

297

"""Rich text logging display."""

298

299

def __init__(self, *, max_lines: int | None = None, **kwargs):

300

"""

301

Initialize a rich log.

302

303

Parameters:

304

- max_lines: Maximum number of log lines to keep

305

"""

306

307

def write(self, content: RenderableType) -> None:

308

"""Write content to the log."""

309

310

def clear(self) -> None:

311

"""Clear all log content."""

312

313

class Log(Widget):

314

"""Simple text logging widget."""

315

316

def write_line(self, line: str) -> None:

317

"""Write a line to the log."""

318

319

def clear(self) -> None:

320

"""Clear the log."""

321

322

class Digits(Widget):

323

"""Large digital display for numbers."""

324

325

def __init__(self, value: str = "", **kwargs):

326

"""

327

Initialize a digits display.

328

329

Parameters:

330

- value: Number to display as string

331

"""

332

333

def update(self, value: str) -> None:

334

"""Update the displayed number."""

335

336

class ProgressBar(Widget):

337

"""Progress indicator bar."""

338

339

def __init__(

340

self,

341

total: float = 100,

342

*,

343

show_eta: bool = True,

344

show_percentage: bool = True,

345

**kwargs

346

):

347

"""

348

Initialize a progress bar.

349

350

Parameters:

351

- total: Total progress value

352

- show_eta: Whether to show estimated time remaining

353

- show_percentage: Whether to show percentage

354

"""

355

356

def advance(self, amount: float = 1) -> None:

357

"""Advance progress by amount."""

358

359

def update(self, *, completed: float = None, total: float = None) -> None:

360

"""Update progress values."""

361

362

# Properties

363

progress: float

364

percentage: float

365

```

366

367

### Navigation and Layout Widgets

368

369

Widgets for organizing content and navigation.

370

371

```python { .api }

372

class Header(Widget):

373

"""Application header bar."""

374

375

def __init__(self, *, show_clock: bool = False, **kwargs):

376

"""

377

Initialize a header.

378

379

Parameters:

380

- show_clock: Whether to display a clock

381

"""

382

383

class Footer(Widget):

384

"""Application footer bar."""

385

386

def __init__(self, **kwargs):

387

"""Initialize a footer."""

388

389

class Tabs(Widget):

390

"""Tab navigation container."""

391

392

class TabActivated(Message):

393

"""Sent when a tab is activated."""

394

def __init__(self, tabs: Tabs, tab: Tab): ...

395

396

def add_tab(self, tab: str | Tab, **kwargs) -> Tab:

397

"""

398

Add a new tab.

399

400

Parameters:

401

- tab: Tab instance or tab label

402

403

Returns:

404

The added Tab instance

405

"""

406

407

def remove_tab(self, tab_id: str) -> None:

408

"""Remove a tab by ID."""

409

410

# Properties

411

active_tab: Tab | None

412

413

class Tab(Widget):

414

"""Individual tab component."""

415

416

def __init__(self, label: str, **kwargs):

417

"""

418

Initialize a tab.

419

420

Parameters:

421

- label: Tab display label

422

"""

423

424

# Properties

425

label: str

426

427

class TabbedContent(Widget):

428

"""Tabbed content container."""

429

430

def add_pane(self, pane: TabPane) -> None:

431

"""Add a content pane."""

432

433

def remove_pane(self, pane_id: str) -> None:

434

"""Remove a content pane."""

435

436

class TabPane(Widget):

437

"""Individual tab content pane."""

438

439

def __init__(self, title: str, **kwargs):

440

"""

441

Initialize a tab pane.

442

443

Parameters:

444

- title: Pane title for the tab

445

"""

446

447

class Tree(Widget):

448

"""Hierarchical tree view."""

449

450

class NodeSelected(Message):

451

"""Sent when a tree node is selected."""

452

453

class NodeExpanded(Message):

454

"""Sent when a tree node is expanded."""

455

456

def __init__(self, label: str, **kwargs):

457

"""

458

Initialize a tree.

459

460

Parameters:

461

- label: Root node label

462

"""

463

464

def add(self, label: str, *, data: Any = None) -> TreeNode:

465

"""

466

Add a child node.

467

468

Parameters:

469

- label: Node display label

470

- data: Associated node data

471

472

Returns:

473

The created TreeNode

474

"""

475

476

def clear(self) -> None:

477

"""Clear all tree nodes."""

478

479

class DirectoryTree(Widget):

480

"""File system directory browser."""

481

482

class DirectorySelected(Message):

483

"""Sent when a directory is selected."""

484

485

class FileSelected(Message):

486

"""Sent when a file is selected."""

487

488

def __init__(self, path: str | Path, **kwargs):

489

"""

490

Initialize a directory tree.

491

492

Parameters:

493

- path: Root directory path

494

"""

495

496

def reload(self) -> None:

497

"""Reload the directory tree."""

498

499

class Collapsible(Widget):

500

"""Expandable/collapsible sections."""

501

502

class Toggled(Message):

503

"""Sent when collapsed state changes."""

504

505

def __init__(

506

self,

507

title: str = "",

508

*,

509

collapsed: bool = True,

510

**kwargs

511

):

512

"""

513

Initialize a collapsible.

514

515

Parameters:

516

- title: Section title

517

- collapsed: Initial collapsed state

518

"""

519

520

def toggle(self) -> None:

521

"""Toggle collapsed/expanded state."""

522

523

# Properties

524

collapsed: bool

525

526

class Rule(Widget):

527

"""Horizontal or vertical separator line."""

528

529

def __init__(

530

self,

531

orientation: str = "horizontal",

532

*,

533

line_style: str = "solid",

534

**kwargs

535

):

536

"""

537

Initialize a rule.

538

539

Parameters:

540

- orientation: "horizontal" or "vertical"

541

- line_style: Line drawing style

542

"""

543

```

544

545

### Data and List Widgets

546

547

Widgets for displaying and interacting with structured data.

548

549

```python { .api }

550

class DataTable(Widget):

551

"""Spreadsheet-like data grid."""

552

553

class RowSelected(Message):

554

"""Sent when a row is selected."""

555

556

class CellSelected(Message):

557

"""Sent when a cell is selected."""

558

559

def __init__(self, *, zebra_stripes: bool = False, **kwargs):

560

"""

561

Initialize a data table.

562

563

Parameters:

564

- zebra_stripes: Whether to alternate row colors

565

"""

566

567

def add_column(

568

self,

569

key: str,

570

*,

571

label: str | None = None,

572

width: int | None = None,

573

**kwargs

574

) -> None:

575

"""

576

Add a table column.

577

578

Parameters:

579

- key: Unique column identifier

580

- label: Column header label

581

- width: Column width in characters

582

"""

583

584

def add_row(self, *cells: Any, **kwargs) -> RowKey:

585

"""

586

Add a data row.

587

588

Parameters:

589

- *cells: Cell values for the row

590

591

Returns:

592

Key identifying the added row

593

"""

594

595

def remove_row(self, row_key: RowKey) -> None:

596

"""Remove a row by key."""

597

598

def clear(self, columns: bool = False) -> None:

599

"""

600

Clear table data.

601

602

Parameters:

603

- columns: Whether to also remove columns

604

"""

605

606

# Properties

607

row_count: int

608

column_count: int

609

610

class ListView(Widget):

611

"""Scrollable list container."""

612

613

class Selected(Message):

614

"""Sent when list item is selected."""

615

616

class Highlighted(Message):

617

"""Sent when list item is highlighted."""

618

619

def __init__(self, *children: ListItem, **kwargs):

620

"""

621

Initialize a list view.

622

623

Parameters:

624

- *children: Initial list items

625

"""

626

627

def append(self, item: ListItem) -> None:

628

"""Add item to end of list."""

629

630

def extend(self, items: Iterable[ListItem]) -> None:

631

"""Add multiple items to list."""

632

633

def clear(self) -> None:

634

"""Remove all list items."""

635

636

# Properties

637

index: int | None

638

639

class ListItem(Widget):

640

"""Individual list item."""

641

642

def __init__(self, child: Widget, **kwargs):

643

"""

644

Initialize a list item.

645

646

Parameters:

647

- child: Widget to display in the item

648

"""

649

650

class OptionList(Widget):

651

"""Selectable option list."""

652

653

class OptionSelected(Message):

654

"""Sent when an option is selected."""

655

656

def __init__(self, *options: str | Option, **kwargs):

657

"""

658

Initialize an option list.

659

660

Parameters:

661

- *options: Initial options

662

"""

663

664

def add_option(self, option: str | Option) -> None:

665

"""Add a new option."""

666

667

def remove_option(self, option_id: str) -> None:

668

"""Remove an option by ID."""

669

670

def clear_options(self) -> None:

671

"""Remove all options."""

672

673

# Properties

674

highlighted: int | None

675

676

class SelectionList(Widget):

677

"""Multi-select list widget."""

678

679

class SelectionToggled(Message):

680

"""Sent when selection changes."""

681

682

def __init__(self, *selections: Selection, **kwargs):

683

"""

684

Initialize a selection list.

685

686

Parameters:

687

- *selections: Initial selections

688

"""

689

690

def select_all(self) -> None:

691

"""Select all items."""

692

693

def deselect_all(self) -> None:

694

"""Deselect all items."""

695

696

# Properties

697

selected: list[int]

698

```

699

700

### Utility and System Widgets

701

702

Specialized widgets for development, loading states, and system functions.

703

704

```python { .api }

705

class Placeholder(Widget):

706

"""Development placeholder widget."""

707

708

def __init__(self, label: str = "Placeholder", **kwargs):

709

"""

710

Initialize a placeholder.

711

712

Parameters:

713

- label: Placeholder display text

714

"""

715

716

class LoadingIndicator(Widget):

717

"""Loading animation indicator."""

718

719

def __init__(self, **kwargs):

720

"""Initialize a loading indicator."""

721

722

class Tooltip(Widget):

723

"""Hover help text."""

724

725

def __init__(self, text: str, **kwargs):

726

"""

727

Initialize a tooltip.

728

729

Parameters:

730

- text: Tooltip text content

731

"""

732

733

class ContentSwitcher(Widget):

734

"""Dynamic content switching widget."""

735

736

def __init__(self, **kwargs):

737

"""Initialize a content switcher."""

738

739

def current(self) -> str | None:

740

"""Get the current content identifier."""

741

742

class Welcome(Widget):

743

"""Welcome screen component."""

744

745

def __init__(self, **kwargs):

746

"""Initialize a welcome screen."""

747

```

748

749

## Usage Examples

750

751

### Form with Input Controls

752

753

```python

754

from textual.app import App

755

from textual.containers import Container, Horizontal

756

from textual.widgets import Button, Input, Checkbox, Select

757

758

class FormApp(App):

759

def compose(self):

760

yield Container(

761

Input(placeholder="Enter your name", id="name"),

762

Input(placeholder="Enter email", id="email"),

763

Select([("Option 1", 1), ("Option 2", 2)], id="choice"),

764

Checkbox("Subscribe to newsletter", id="subscribe"),

765

Horizontal(

766

Button("Submit", variant="primary", id="submit"),

767

Button("Cancel", id="cancel"),

768

),

769

id="form"

770

)

771

772

def on_button_pressed(self, event: Button.Pressed):

773

if event.button.id == "submit":

774

name = self.query_one("#name", Input).value

775

email = self.query_one("#email", Input).value

776

choice = self.query_one("#choice", Select).value

777

newsletter = self.query_one("#subscribe", Checkbox).value

778

779

self.log(f"Form submitted: {name}, {email}, {choice}, {newsletter}")

780

```

781

782

### Data Table

783

784

```python

785

from textual.app import App

786

from textual.widgets import DataTable

787

788

class TableApp(App):

789

def compose(self):

790

yield DataTable(zebra_stripes=True)

791

792

def on_mount(self):

793

table = self.query_one(DataTable)

794

795

# Add columns

796

table.add_column("Name", key="name")

797

table.add_column("Age", key="age")

798

table.add_column("City", key="city")

799

800

# Add rows

801

table.add_row("Alice", 30, "New York")

802

table.add_row("Bob", 25, "London")

803

table.add_row("Carol", 35, "Tokyo")

804

```