- Fixed DataTable row selection and event handling - Added explicit column keys to prevent auto-generated keys - Implemented row-to-flow mapping for reliable selection tracking - Converted left metrics panel to horizontal top bar - Fixed all missing FlowStats/EnhancedAnalysisData attributes - Created comprehensive Textual API documentation in Documentation/textual/ - Added validation checklist to prevent future API mismatches - Preserved cursor position during data refreshes - Fixed RowKey type handling and event names The TUI now properly handles flow selection, displays metrics in a compact top bar, and correctly correlates selected rows with the details pane.
5.7 KiB
5.7 KiB
DataTable Widget API Reference
Overview
The DataTable widget displays tabular data with support for selection, scrolling, and styling.
Import
from textual.widgets import DataTable
Class Hierarchy
Widget → ScrollView → DataTable
Constructor
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 rowscolumns: list[Column]- List of columnsrow_count: int- Number of rowscolumn_count: int- Number of columns
Methods
Adding Data
# 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
# 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
# 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
# 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
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
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
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
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
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()methodset_cell_style()method
Use CSS classes and selectors instead:
DataTable > .datatable--cursor {
background: $primary 30%;
}
DataTable > .datatable--header {
text-style: bold;
}
Type Hints
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
-
TypeError: 'RowKey' is not iterable
- Solution: Convert to string first:
str(row_key)
- Solution: Convert to string first:
-
AttributeError: 'DataTable' has no attribute 'set_row_style'
- Solution: Use CSS styling instead
-
Event not firing
- Check handler name:
on_data_table_row_highlightednoton_data_table_cursor_moved
- Check handler name: