CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-textual

Modern Text User Interface framework for building cross-platform terminal and web applications with Python

Overall
score

93%

Overview
Eval results
Files

widgets.mddocs/

Widget Library

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

Capabilities

Input and Form Controls

Interactive widgets for user input and form creation.

class Button(Widget):
    """A clickable button widget."""
    
    class Pressed(Message):
        """Sent when the button is pressed."""
        def __init__(self, button: Button): ...
    
    def __init__(
        self, 
        label: RenderableType = "", 
        *, 
        variant: str = "default", 
        disabled: bool = False,
        **kwargs
    ):
        """
        Initialize a button.
        
        Parameters:
        - label: Button text or renderable content  
        - variant: Button style ("default", "primary", "success", "warning", "error")
        - disabled: Whether the button is disabled
        """
    
    def press(self) -> None:
        """Programmatically press the button."""

class Input(Widget):
    """Single-line text input widget."""
    
    class Changed(Message):
        """Sent when input value changes."""
        def __init__(self, input: Input, value: str): ...
    
    class Submitted(Message):
        """Sent when input is submitted (Enter key)."""
        def __init__(self, input: Input, value: str): ...
    
    def __init__(
        self,
        value: str = "",
        placeholder: str = "",
        *,
        password: bool = False,
        restrict: str | None = None,
        type: str = "text",
        max_length: int = 0,
        **kwargs
    ):
        """
        Initialize an input widget.
        
        Parameters:
        - value: Initial input value
        - placeholder: Placeholder text when empty
        - password: Whether to hide input characters
        - restrict: Regex pattern to restrict input
        - type: Input type ("text", "integer", "number")
        - max_length: Maximum input length (0 for unlimited)
        """
    
    # Properties
    value: str
    placeholder: str
    cursor_position: int

class TextArea(Widget):
    """Multi-line text editor with syntax highlighting."""
    
    class Changed(Message):
        """Sent when text content changes."""
    
    def __init__(
        self,
        text: str = "",
        *,
        language: str | None = None,
        theme: str = "monokai",
        soft_wrap: bool = True,
        tab_size: int = 4,
        **kwargs
    ):
        """
        Initialize a text area.
        
        Parameters:
        - text: Initial text content
        - language: Programming language for syntax highlighting
        - theme: Color theme for highlighting
        - soft_wrap: Whether to wrap long lines
        - tab_size: Number of spaces per tab
        """
    
    def load_text(self, text: str) -> None:
        """Load new text content."""
    
    # Properties
    text: str
    cursor_position: tuple[int, int]

class Checkbox(Widget):
    """Boolean checkbox input."""
    
    class Changed(Message):
        """Sent when checkbox state changes."""
        def __init__(self, checkbox: Checkbox, value: bool): ...
    
    def __init__(self, label: str = "", *, value: bool = False, **kwargs):
        """
        Initialize a checkbox.
        
        Parameters:
        - label: Checkbox label text
        - value: Initial checked state
        """
    
    def toggle(self) -> None:
        """Toggle the checkbox state."""
    
    # Properties
    value: bool

class Switch(Widget):
    """Toggle switch control."""
    
    class Changed(Message):
        """Sent when switch state changes."""
    
    def __init__(self, *, value: bool = False, **kwargs):
        """
        Initialize a switch.
        
        Parameters:
        - value: Initial switch state
        """
    
    def toggle(self) -> None:
        """Toggle the switch state."""
    
    # Properties  
    value: bool

class RadioButton(Widget):
    """Individual radio button."""
    
    class Changed(Message):
        """Sent when radio button selection changes."""
    
    def __init__(self, label: str = "", *, value: bool = False, **kwargs):
        """
        Initialize a radio button.
        
        Parameters:
        - label: Radio button label
        - value: Whether this button is selected
        """
    
    # Properties
    value: bool

class RadioSet(Widget):
    """Group of radio buttons."""
    
    class Changed(Message):
        """Sent when selection changes."""
        def __init__(self, radio_set: RadioSet, pressed: RadioButton): ...
    
    def __init__(self, *labels: str, **kwargs):
        """
        Initialize a radio set.
        
        Parameters:
        - *labels: Radio button labels
        """
    
    # Properties
    pressed_button: RadioButton | None
    pressed_index: int

class Select(Widget):
    """Dropdown selection widget."""
    
    class Changed(Message):
        """Sent when selection changes."""
    
    def __init__(
        self,
        options: Iterable[tuple[str, Any]] | Iterable[str],
        *,
        value: Any = None,
        allow_blank: bool = True,
        **kwargs
    ):
        """
        Initialize a select widget.
        
        Parameters:
        - options: Selection options as (label, value) tuples or strings
        - value: Initial selected value
        - allow_blank: Whether to allow no selection
        """
    
    # Properties
    value: Any
    options: list[tuple[str, Any]]

Display and Content Widgets

Widgets for displaying static and dynamic content.

class Static(Widget):
    """Display static rich content."""
    
    def __init__(self, renderable: RenderableType = "", **kwargs):
        """
        Initialize a static widget.
        
        Parameters:
        - renderable: Content to display (string, Rich object, etc.)
        """
    
    def update(self, renderable: RenderableType) -> None:
        """Update the displayed content."""

class Label(Widget):
    """Simple text label."""
    
    def __init__(self, text: str = "", **kwargs):
        """
        Initialize a label.
        
        Parameters:
        - text: Label text content
        """
    
    # Properties
    text: str

class Pretty(Widget):
    """Pretty-printed Python objects using Rich."""
    
    def __init__(self, obj: Any, **kwargs):
        """
        Initialize a pretty widget.
        
        Parameters:
        - obj: Python object to pretty-print
        """
    
    def update(self, obj: Any) -> None:
        """Update the displayed object."""

class Markdown(Widget):
    """Markdown content renderer."""
    
    class LinkClicked(Message):
        """Sent when a markdown link is clicked."""
    
    def __init__(self, markdown: str = "", **kwargs):
        """
        Initialize a markdown widget.
        
        Parameters:
        - markdown: Markdown text content
        """
    
    # Properties
    markdown: str

class MarkdownViewer(Widget):
    """Scrollable markdown viewer with navigation."""
    
    def __init__(self, markdown: str = "", **kwargs):
        """
        Initialize a markdown viewer.
        
        Parameters:
        - markdown: Markdown content to display
        """
    
    def go(self, location: str) -> None:
        """Navigate to a specific location in the document."""

class RichLog(Widget):
    """Rich text logging display."""
    
    def __init__(self, *, max_lines: int | None = None, **kwargs):
        """
        Initialize a rich log.
        
        Parameters:
        - max_lines: Maximum number of log lines to keep
        """
    
    def write(self, content: RenderableType) -> None:
        """Write content to the log."""
    
    def clear(self) -> None:
        """Clear all log content."""

class Log(Widget):
    """Simple text logging widget."""
    
    def write_line(self, line: str) -> None:
        """Write a line to the log."""
    
    def clear(self) -> None:
        """Clear the log."""

class Digits(Widget):
    """Large digital display for numbers."""
    
    def __init__(self, value: str = "", **kwargs):
        """
        Initialize a digits display.
        
        Parameters:
        - value: Number to display as string
        """
    
    def update(self, value: str) -> None:
        """Update the displayed number."""

class ProgressBar(Widget):
    """Progress indicator bar."""
    
    def __init__(
        self,
        total: float = 100,
        *,
        show_eta: bool = True,
        show_percentage: bool = True,
        **kwargs
    ):
        """
        Initialize a progress bar.
        
        Parameters:
        - total: Total progress value
        - show_eta: Whether to show estimated time remaining
        - show_percentage: Whether to show percentage
        """
    
    def advance(self, amount: float = 1) -> None:
        """Advance progress by amount."""
    
    def update(self, *, completed: float = None, total: float = None) -> None:
        """Update progress values."""
    
    # Properties
    progress: float
    percentage: float

Navigation and Layout Widgets

Widgets for organizing content and navigation.

class Header(Widget):
    """Application header bar."""
    
    def __init__(self, *, show_clock: bool = False, **kwargs):
        """
        Initialize a header.
        
        Parameters:
        - show_clock: Whether to display a clock
        """

class Footer(Widget):
    """Application footer bar."""
    
    def __init__(self, **kwargs):
        """Initialize a footer."""

class Tabs(Widget):
    """Tab navigation container."""
    
    class TabActivated(Message):
        """Sent when a tab is activated."""
        def __init__(self, tabs: Tabs, tab: Tab): ...
    
    def add_tab(self, tab: str | Tab, **kwargs) -> Tab:
        """
        Add a new tab.
        
        Parameters:
        - tab: Tab instance or tab label
        
        Returns:
        The added Tab instance
        """
    
    def remove_tab(self, tab_id: str) -> None:
        """Remove a tab by ID."""
    
    # Properties
    active_tab: Tab | None

class Tab(Widget):  
    """Individual tab component."""
    
    def __init__(self, label: str, **kwargs):
        """
        Initialize a tab.
        
        Parameters:
        - label: Tab display label
        """
    
    # Properties
    label: str

class TabbedContent(Widget):
    """Tabbed content container."""
    
    def add_pane(self, pane: TabPane) -> None:
        """Add a content pane."""
    
    def remove_pane(self, pane_id: str) -> None:
        """Remove a content pane."""

class TabPane(Widget):
    """Individual tab content pane."""
    
    def __init__(self, title: str, **kwargs):
        """
        Initialize a tab pane.
        
        Parameters:
        - title: Pane title for the tab
        """

class Tree(Widget):
    """Hierarchical tree view."""
    
    class NodeSelected(Message):
        """Sent when a tree node is selected."""
    
    class NodeExpanded(Message):
        """Sent when a tree node is expanded."""
    
    def __init__(self, label: str, **kwargs):
        """
        Initialize a tree.
        
        Parameters:
        - label: Root node label
        """
    
    def add(self, label: str, *, data: Any = None) -> TreeNode:
        """
        Add a child node.
        
        Parameters:
        - label: Node display label
        - data: Associated node data
        
        Returns:
        The created TreeNode
        """
    
    def clear(self) -> None:
        """Clear all tree nodes."""

class DirectoryTree(Widget):
    """File system directory browser."""
    
    class DirectorySelected(Message):
        """Sent when a directory is selected."""
    
    class FileSelected(Message):
        """Sent when a file is selected."""
    
    def __init__(self, path: str | Path, **kwargs):
        """
        Initialize a directory tree.
        
        Parameters:
        - path: Root directory path
        """
    
    def reload(self) -> None:
        """Reload the directory tree."""

class Collapsible(Widget):
    """Expandable/collapsible sections."""
    
    class Toggled(Message):
        """Sent when collapsed state changes."""
    
    def __init__(
        self,
        title: str = "",
        *,
        collapsed: bool = True,
        **kwargs
    ):
        """
        Initialize a collapsible.
        
        Parameters:
        - title: Section title
        - collapsed: Initial collapsed state
        """
    
    def toggle(self) -> None:
        """Toggle collapsed/expanded state."""
    
    # Properties
    collapsed: bool

class Rule(Widget):
    """Horizontal or vertical separator line."""
    
    def __init__(
        self,
        orientation: str = "horizontal",
        *,
        line_style: str = "solid",
        **kwargs
    ):
        """
        Initialize a rule.
        
        Parameters:
        - orientation: "horizontal" or "vertical"
        - line_style: Line drawing style
        """

Data and List Widgets

Widgets for displaying and interacting with structured data.

class DataTable(Widget):
    """Spreadsheet-like data grid."""
    
    class RowSelected(Message):
        """Sent when a row is selected."""
    
    class CellSelected(Message):
        """Sent when a cell is selected."""
    
    def __init__(self, *, zebra_stripes: bool = False, **kwargs):
        """
        Initialize a data table.
        
        Parameters:
        - zebra_stripes: Whether to alternate row colors
        """
    
    def add_column(
        self,
        key: str,
        *,
        label: str | None = None,
        width: int | None = None,
        **kwargs
    ) -> None:
        """
        Add a table column.
        
        Parameters:
        - key: Unique column identifier
        - label: Column header label
        - width: Column width in characters
        """
    
    def add_row(self, *cells: Any, **kwargs) -> RowKey:
        """
        Add a data row.
        
        Parameters:
        - *cells: Cell values for the row
        
        Returns:
        Key identifying the added row
        """
    
    def remove_row(self, row_key: RowKey) -> None:
        """Remove a row by key."""
    
    def clear(self, columns: bool = False) -> None:
        """
        Clear table data.
        
        Parameters:
        - columns: Whether to also remove columns
        """
    
    # Properties
    row_count: int
    column_count: int

class ListView(Widget):
    """Scrollable list container."""
    
    class Selected(Message):
        """Sent when list item is selected."""
    
    class Highlighted(Message):
        """Sent when list item is highlighted."""
    
    def __init__(self, *children: ListItem, **kwargs):
        """
        Initialize a list view.
        
        Parameters:
        - *children: Initial list items
        """
    
    def append(self, item: ListItem) -> None:
        """Add item to end of list."""
    
    def extend(self, items: Iterable[ListItem]) -> None:
        """Add multiple items to list."""
    
    def clear(self) -> None:
        """Remove all list items."""
    
    # Properties  
    index: int | None

class ListItem(Widget):
    """Individual list item."""
    
    def __init__(self, child: Widget, **kwargs):
        """
        Initialize a list item.
        
        Parameters:
        - child: Widget to display in the item
        """

class OptionList(Widget):
    """Selectable option list."""
    
    class OptionSelected(Message):
        """Sent when an option is selected."""
    
    def __init__(self, *options: str | Option, **kwargs):
        """
        Initialize an option list.
        
        Parameters:
        - *options: Initial options
        """
    
    def add_option(self, option: str | Option) -> None:
        """Add a new option."""
    
    def remove_option(self, option_id: str) -> None:
        """Remove an option by ID."""
    
    def clear_options(self) -> None:
        """Remove all options."""
    
    # Properties
    highlighted: int | None

class SelectionList(Widget):
    """Multi-select list widget."""
    
    class SelectionToggled(Message):
        """Sent when selection changes."""
    
    def __init__(self, *selections: Selection, **kwargs):
        """
        Initialize a selection list.
        
        Parameters:
        - *selections: Initial selections
        """
    
    def select_all(self) -> None:
        """Select all items."""
    
    def deselect_all(self) -> None:
        """Deselect all items."""
    
    # Properties
    selected: list[int]

Utility and System Widgets

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

class Placeholder(Widget):
    """Development placeholder widget."""
    
    def __init__(self, label: str = "Placeholder", **kwargs):
        """
        Initialize a placeholder.
        
        Parameters:
        - label: Placeholder display text
        """

class LoadingIndicator(Widget):
    """Loading animation indicator."""
    
    def __init__(self, **kwargs):
        """Initialize a loading indicator."""

class Tooltip(Widget):
    """Hover help text."""
    
    def __init__(self, text: str, **kwargs):
        """
        Initialize a tooltip.
        
        Parameters:
        - text: Tooltip text content
        """

class ContentSwitcher(Widget):
    """Dynamic content switching widget."""
    
    def __init__(self, **kwargs):
        """Initialize a content switcher."""
    
    def current(self) -> str | None:
        """Get the current content identifier."""

class Welcome(Widget):
    """Welcome screen component."""
    
    def __init__(self, **kwargs):
        """Initialize a welcome screen."""

Usage Examples

Form with Input Controls

from textual.app import App
from textual.containers import Container, Horizontal
from textual.widgets import Button, Input, Checkbox, Select

class FormApp(App):
    def compose(self):
        yield Container(
            Input(placeholder="Enter your name", id="name"),
            Input(placeholder="Enter email", id="email"),
            Select([("Option 1", 1), ("Option 2", 2)], id="choice"),
            Checkbox("Subscribe to newsletter", id="subscribe"),
            Horizontal(
                Button("Submit", variant="primary", id="submit"),
                Button("Cancel", id="cancel"),
            ),
            id="form"
        )
    
    def on_button_pressed(self, event: Button.Pressed):
        if event.button.id == "submit":
            name = self.query_one("#name", Input).value
            email = self.query_one("#email", Input).value
            choice = self.query_one("#choice", Select).value
            newsletter = self.query_one("#subscribe", Checkbox).value
            
            self.log(f"Form submitted: {name}, {email}, {choice}, {newsletter}")

Data Table

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

class TableApp(App):
    def compose(self):
        yield DataTable(zebra_stripes=True)
    
    def on_mount(self):
        table = self.query_one(DataTable)
        
        # Add columns
        table.add_column("Name", key="name")
        table.add_column("Age", key="age")
        table.add_column("City", key="city")
        
        # Add rows
        table.add_row("Alice", 30, "New York")
        table.add_row("Bob", 25, "London")
        table.add_row("Carol", 35, "Tokyo")

Install with Tessl CLI

npx tessl i tessl/pypi-textual

docs

content.md

core-framework.md

events.md

index.md

styling.md

testing.md

widgets.md

tile.json