# DataTable Widget API Reference ## Overview The DataTable widget displays tabular data with support for selection, scrolling, and styling. ## Import ```python from textual.widgets import DataTable ``` ## Class Hierarchy ``` Widget → ScrollView → DataTable ``` ## Constructor ```python DataTable( *, show_header: bool = True, fixed_rows: int = 0, fixed_columns: int = 0, zebra_stripes: bool = False, header_height: int = 1, show_cursor: bool = True, cursor_foreground_priority: Literal["renderable", "css"] = "renderable", cursor_background_priority: Literal["renderable", "css"] = "renderable", cursor_type: CursorType = "cell", cell_padding: int = 1, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False ) ``` ## Key Properties ### Cursor Properties - `cursor_row: int` - Current cursor row (0-based) - `cursor_column: int` - Current cursor column (0-based) - `cursor_coordinate: Coordinate` - (row, column) tuple ### Table Properties - `rows: Mapping[RowKey, Row]` - Dictionary of rows - `columns: list[Column]` - List of columns - `row_count: int` - Number of rows - `column_count: int` - Number of columns ## Methods ### Adding Data ```python # Add columns add_column(label: TextType, *, width: int | None = None, key: str | None = None, default: CellType | None = None) -> ColumnKey # Add multiple columns add_columns(*labels: TextType) -> list[ColumnKey] # Add a single row add_row(*cells: CellType, height: int | None = 1, key: str | None = None, label: TextType | None = None) -> RowKey # Add multiple rows add_rows(rows: Iterable[Iterable[CellType]]) -> list[RowKey] ``` ### Modifying Data ```python # Update a cell update_cell(row_key: RowKey, column_key: ColumnKey, value: CellType, *, update_width: bool = False) -> None # Update cell at coordinate update_cell_at(coordinate: Coordinate, value: CellType, *, update_width: bool = False) -> None # Remove row remove_row(row_key: RowKey) -> None # Remove column remove_column(column_key: ColumnKey) -> None # Clear all data clear(columns: bool = False) -> Self ``` ### Navigation ```python # Move cursor move_cursor(row: int | None = None, column: int | None = None, animate: bool = True, scroll: bool = True) -> None # Scroll to coordinate scroll_to(x: float | None = None, y: float | None = None, *, animate: bool = True, speed: float | None = None, duration: float | None = None, ...) -> None ``` ### Sorting ```python # Sort by column(s) sort(*columns: ColumnKey | str, reverse: bool = False) -> Self # Sort with custom key sort(key: Callable[[Any], Any], *, reverse: bool = False) -> Self ``` ## Events ### Selection Events ```python class RowSelected(Message): """Posted when a row is selected (Enter key).""" row_key: RowKey row_index: int class CellSelected(Message): """Posted when a cell is selected.""" coordinate: Coordinate cell_key: CellKey class RowHighlighted(Message): """Posted when cursor highlights a row.""" row_key: RowKey row_index: int class CellHighlighted(Message): """Posted when cursor highlights a cell.""" coordinate: Coordinate cell_key: CellKey class ColumnHighlighted(Message): """Posted when cursor highlights a column.""" column_key: ColumnKey column_index: int ``` ### Header Events ```python class HeaderSelected(Message): """Posted when a column header is clicked.""" column_key: ColumnKey column_index: int label: Text class RowLabelSelected(Message): """Posted when a row label is clicked.""" row_key: RowKey row_index: int label: Text ``` ## Common Patterns ### Creating a DataTable ```python class MyWidget(Widget): def compose(self) -> ComposeResult: yield DataTable(id="my-table") def on_mount(self) -> None: table = self.query_one("#my-table", DataTable) table.add_columns("Name", "Value", "Status") table.add_row("Item 1", "100", "Active", key="item_1") ``` ### Handling Selection ```python def on_data_table_row_highlighted(self, event: DataTable.RowHighlighted) -> None: # React to cursor movement self.selected_row = event.row_key def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None: # React to Enter key press self.process_selection(event.row_key) ``` ### Preserving Cursor Position ```python def refresh_table(self): table = self.query_one(DataTable) # Save position cursor_row = table.cursor_row selected_key = list(table.rows.keys())[cursor_row] if table.rows else None # Update data table.clear() # ... add new data ... # Restore position if selected_key and selected_key in table.rows: row_index = list(table.rows.keys()).index(selected_key) table.move_cursor(row=row_index, animate=False) ``` ## Styling DataTable supports CSS styling but does NOT have: - `set_row_style()` method - `set_cell_style()` method Use CSS classes and selectors instead: ```css DataTable > .datatable--cursor { background: $primary 30%; } DataTable > .datatable--header { text-style: bold; } ``` ## Type Hints ```python from textual.widgets.data_table import RowKey, ColumnKey, CellKey from textual.coordinate import Coordinate # RowKey and ColumnKey are not strings - convert with str() if needed row_key_str = str(row_key) ``` ## Common Errors and Solutions 1. **TypeError: 'RowKey' is not iterable** - Solution: Convert to string first: `str(row_key)` 2. **AttributeError: 'DataTable' has no attribute 'set_row_style'** - Solution: Use CSS styling instead 3. **Event not firing** - Check handler name: `on_data_table_row_highlighted` not `on_data_table_cursor_moved`