Skip to content

DataTable#

A Material Design data table.

ft.DataTable(
    columns=[
        ft.DataColumn(label=ft.Text("Name")),
        ft.DataColumn(label=ft.Text("Role")),
    ],
    rows=[
        ft.DataRow(
            cells=[
                ft.DataCell(ft.Text("Alice")),
                ft.DataCell(ft.Text("Engineer")),
            ]
        ),
        ft.DataRow(
            cells=[
                ft.DataCell(ft.Text("Bob")),
                ft.DataCell(ft.Text("Designer")),
            ]
        ),
    ],
)

DataTable

Basic DataTable

Inherits: LayoutControl

Properties

Events

Examples#

Live example

Basic Example#

import flet as ft


def main(page: ft.Page):
    page.add(
        ft.DataTable(
            columns=[
                ft.DataColumn(label=ft.Text("First name")),
                ft.DataColumn(label=ft.Text("Last name")),
                ft.DataColumn(label=ft.Text("Age"), numeric=True),
            ],
            rows=[
                ft.DataRow(
                    cells=[
                        ft.DataCell(ft.Text("John")),
                        ft.DataCell(ft.Text("Smith")),
                        ft.DataCell(ft.Text("43")),
                    ],
                ),
                ft.DataRow(
                    cells=[
                        ft.DataCell(ft.Text("Jack")),
                        ft.DataCell(ft.Text("Brown")),
                        ft.DataCell(ft.Text("19")),
                    ],
                ),
                ft.DataRow(
                    cells=[
                        ft.DataCell(ft.Text("Alice")),
                        ft.DataCell(ft.Text("Wong")),
                        ft.DataCell(ft.Text("25")),
                    ],
                ),
            ],
        ),
    )


ft.run(main)

basic

Sortable columns and selectable rows#

import flet as ft


def main(page: ft.Page):
    page.add(
        ft.DataTable(
            width=700,
            bgcolor=ft.Colors.YELLOW,
            border=ft.border.all(2, ft.Colors.RED),
            border_radius=10,
            vertical_lines=ft.border.BorderSide(3, ft.Colors.BLUE),
            horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN),
            sort_column_index=0,
            sort_ascending=True,
            heading_row_color=ft.Colors.BLACK12,
            heading_row_height=100,
            data_row_color={ft.ControlState.HOVERED: "0x30FF0000"},
            show_checkbox_column=True,
            divider_thickness=0,
            column_spacing=200,
            columns=[
                ft.DataColumn(
                    label=ft.Text("Column 1"),
                    on_sort=lambda e: print(f"{e.column_index}, {e.ascending}"),
                ),
                ft.DataColumn(
                    label=ft.Text("Column 2"),
                    tooltip="This is a second column",
                    numeric=True,
                    on_sort=lambda e: print(f"{e.column_index}, {e.ascending}"),
                ),
            ],
            rows=[
                ft.DataRow(
                    cells=[ft.DataCell(ft.Text("A")), ft.DataCell(ft.Text("1"))],
                    selected=True,
                    on_select_change=lambda e: print(f"row select changed: {e.data}"),
                ),
                ft.DataRow([ft.DataCell(ft.Text("B")), ft.DataCell(ft.Text("2"))]),
            ],
        ),
    )


ft.run(main)

sortable-and-selectable

Handling events#

import flet as ft


def main(page: ft.Page):
    def handle_row_selection_change(e: ft.Event[ft.DataRow]):
        match e.control.data:
            case 1:
                row1.selected = not row1.selected
            case 2:
                row2.selected = not row2.selected
            case 3:
                row3.selected = not row3.selected
        page.update()

    def handle_column_sort(e: ft.DataColumnSortEvent):
        match e.control.data:
            case 1:
                print(f"{e.column_index}, {e.ascending}")
                # table.sort_column_index = 1
                table.sort_ascending = e.ascending
            case 2:
                print(f"{e.column_index}, {e.ascending}")
                # table.sort_column_index = 2
                table.sort_ascending = e.ascending
        page.update()

    page.add(
        table := ft.DataTable(
            width=700,
            bgcolor=ft.Colors.TEAL_ACCENT_200,
            border=ft.Border.all(2, ft.Colors.RED_ACCENT_200),
            border_radius=10,
            vertical_lines=ft.border.BorderSide(3, ft.Colors.BLUE_600),
            horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN_600),
            sort_column_index=0,
            sort_ascending=True,
            heading_row_color=ft.Colors.BLACK12,
            heading_row_height=100,
            data_row_color={ft.ControlState.HOVERED: "0x30FF0000"},
            show_checkbox_column=True,
            divider_thickness=0,
            column_spacing=200,
            columns=[
                ft.DataColumn(
                    label=ft.Text("Column 1"),
                    tooltip="This is the first column",
                    data=1,
                    on_sort=handle_column_sort,
                ),
                ft.DataColumn(
                    label=ft.Text("Column 2"),
                    tooltip="This is a second column",
                    numeric=True,
                    data=2,
                    on_sort=handle_column_sort,
                ),
            ],
            rows=[
                row1 := ft.DataRow(
                    cells=[ft.DataCell(ft.Text("A")), ft.DataCell(ft.Text("1"))],
                    selected=True,
                    on_select_change=handle_row_selection_change,
                    data=1,
                ),
                row2 := ft.DataRow(
                    cells=[ft.DataCell(ft.Text("B")), ft.DataCell(ft.Text("2"))],
                    selected=False,
                    on_select_change=handle_row_selection_change,
                    data=2,
                ),
                row3 := ft.DataRow(
                    cells=[ft.DataCell(ft.Text("C")), ft.DataCell(ft.Text("3"))],
                    selected=False,
                    on_select_change=handle_row_selection_change,
                    data=3,
                ),
            ],
        )
    )


ft.run(main)

Properties#

bgcolor class-attribute instance-attribute #

bgcolor: ColorValue | None = None

The background color for this table.

border class-attribute instance-attribute #

border: Border | None = None

The border around the table.

border_radius class-attribute instance-attribute #

border_radius: BorderRadiusValue | None = None

Border corners.

checkbox_horizontal_margin class-attribute instance-attribute #

checkbox_horizontal_margin: Number | None = None

Horizontal margin around the checkbox, if it is displayed.

clip_behavior class-attribute instance-attribute #

clip_behavior: ClipBehavior = NONE

Defines how the contents of this table are clipped.

column_spacing class-attribute instance-attribute #

column_spacing: Number | None = None

The horizontal margin between the contents of each data column.

columns instance-attribute #

columns: list[DataColumn]

A list of DataColumn controls describing table columns.

Raises:

data_row_color class-attribute instance-attribute #

data_row_color: ControlStateValue[ColorValue] | None = None

The background color for the data rows.

The effective background color can be made to depend on the ControlState state, i.e. if the row is selected, pressed, hovered, focused, disabled or enabled. The color is painted as an overlay to the row. To make sure that the row's InkWell is visible (when pressed, hovered and focused), it is recommended to use a translucent background color.

data_row_max_height class-attribute instance-attribute #

data_row_max_height: Number | None = None

The maximum height of each row (excluding the row that contains column headings). Set to float("inf") for the height of each row to adjust automatically with its content.

Defaults to 48.0.

Note

Must be greater than or equal to data_row_min_height.

Raises:

data_row_min_height class-attribute instance-attribute #

data_row_min_height: Number | None = None

The minimum height of each row (excluding the row that contains column headings).

Defaults to 48.0.

Note

Must be less than or equal to data_row_max_height.

Raises:

data_text_style class-attribute instance-attribute #

data_text_style: TextStyle | None = None

The text style of the data rows.

divider_thickness class-attribute instance-attribute #

divider_thickness: Number = 1.0

The width of the divider that appears between rows.

Note

Must be greater than or equal to zero.

Raises:

gradient class-attribute instance-attribute #

gradient: Gradient | None = None

The background gradient of this table.

heading_row_color class-attribute instance-attribute #

heading_row_color: ControlStateValue[ColorValue] | None = (
    None
)

The background color for the heading row.

The effective background color can be made to depend on the ControlState state, i.e. if the row is pressed, hovered, focused when sorted. The color is painted as an overlay to the row. To make sure that the row's InkWell is visible (when pressed, hovered and focused), it is recommended to use a translucent color.

heading_row_height class-attribute instance-attribute #

heading_row_height: Number | None = None

The height of the heading row.

heading_text_style class-attribute instance-attribute #

heading_text_style: TextStyle | None = None

The text style for the heading row.

horizontal_lines class-attribute instance-attribute #

horizontal_lines: BorderSide | None = None

Set the color and width of horizontal lines between rows.

horizontal_margin class-attribute instance-attribute #

horizontal_margin: Number | None = None

The horizontal margin between the edges of this table and the content in the first and last cells of each row.

When a checkbox is displayed, it is also the margin between the checkbox the content in the first data column.

rows class-attribute instance-attribute #

rows: list[DataRow] = field(default_factory=list)

A list of DataRow controls defining table rows.

Raises:

show_bottom_border class-attribute instance-attribute #

show_bottom_border: bool = False

Whether a border at the bottom of the table is displayed.

By default, a border is not shown at the bottom to allow for a border around the table defined by decoration.

show_checkbox_column class-attribute instance-attribute #

show_checkbox_column: bool = False

Whether the control should display checkboxes for selectable rows.

If True, a checkbox will be placed at the beginning of each row that is selectable. However, if DataRow.on_select_change is not set for any row, checkboxes will not be placed, even if this value is True.

If False, all rows will not display a checkbox.

sort_ascending class-attribute instance-attribute #

sort_ascending: bool = False

Whether the column mentioned in sort_column_index, if any, is sorted in ascending order.

If True, the order is ascending (meaning the rows with the smallest values for the current sort column are first in the table).

If False, the order is descending (meaning the rows with the smallest values for the current sort column are last in the table).

sort_column_index class-attribute instance-attribute #

sort_column_index: int | None = None

The current primary sort key's column.

If specified, indicates that the indicated column is the column by which the data is sorted. The number must correspond to the index of the relevant column in columns.

Setting this will cause the relevant column to have a sort indicator displayed.

When this is None, it implies that the table's sort order does not correspond to any of the columns.

Raises:

vertical_lines class-attribute instance-attribute #

vertical_lines: BorderSide | None = None

Set the color and width of vertical lines between columns.

Events#

on_select_all class-attribute instance-attribute #

on_select_all: ControlEventHandler[DataTable] | None = None

Invoked when the user selects or unselects every row, using the checkbox in the heading row.

If this is None, then the DataRow.on_select_change callback of every row of this table is invoked appropriately instead.

Tip

To control whether a particular row is selectable or not, see DataRow.on_select_change. This callback is only relevant if any row is selectable.