Skip to content

DataGrid

DataGrid is an advanced table component with sorting, filtering, pagination, bulk actions, column toggling, and CSV export. It's powered by htmx for seamless interactions.

Quick Start

from fastapi import Request
from kokage_ui import DataGrid, DataGridState

@ui.fragment("/items/_list")
async def items_list(request: Request):
    state = DataGridState.from_request(request)
    skip = (state.page - 1) * 20
    items, total = await storage.list(skip=skip, limit=20, search=None)
    total_pages = max(1, -(-total // 20))

    return DataGrid(
        Item,
        items,
        data_url="/items/_list",
        sort_field=state.sort_field,
        sort_order=state.sort_order,
        page=state.page,
        total_pages=total_pages,
        total_items=total,
    )

DataGrid Parameters

Parameter Type Description
model type[BaseModel] Pydantic model class
rows list[BaseModel] Data rows to display
data_url str htmx endpoint for all interactions
grid_id str HTML id (default: "datagrid")
exclude list[str] | None Fields to exclude
include list[str] | None Fields to include (whitelist)
sort_field str | None Current sort field
sort_order str "asc" or "desc" (default: "asc")
filters dict[str, ColumnFilter] | None Per-column filters
filter_values dict[str, str] | None Current filter values
bulk_actions list[tuple[str, str]] | None [(label, action_url), ...]
id_field str Primary key field (default: "id")
column_toggle bool Enable column visibility toggle
visible_columns list[str] | None Currently visible columns
cell_renderers dict[str, Callable] | None Custom cell renderers
extra_columns dict[str, Callable] | None Additional columns {name: (row) -> Component}
page int Current page (default: 1)
total_pages int Total pages
total_items int Total item count
per_page int Items per page (default: 20)
csv_url str | None CSV export endpoint URL
zebra bool Zebra-striped rows (default: True)
compact bool Compact table style (default: False)

DataGridState

Parse grid state from request query parameters:

state = DataGridState.from_request(request)
# state.sort_field   → "name"
# state.sort_order   → "asc"
# state.page         → 2
# state.filter_values → {"f_name": "alice"}
# state.clean_filters → {"name": "alice"}  (without f_ prefix)

Query parameters: sort=field, order=asc|desc, page=N, f_name=value (filters), col=field (visible columns).

ColumnFilter

Define per-column filter inputs:

from kokage_ui import ColumnFilter

filters = {
    "name": ColumnFilter(type="text", placeholder="Filter name..."),
    "status": ColumnFilter(type="select", options=[("active", "Active"), ("inactive", "Inactive")]),
    "price": ColumnFilter(type="number_range"),
}
Type Description
"text" Text input with debounced keyup
"select" Dropdown with predefined options
"number_range" Min/max number inputs

Custom Cell Renderers

DataGrid(
    Item,
    items,
    data_url="/items/_list",
    cell_renderers={
        "id": lambda v: A(str(v), href=f"/items/{v}"),
        "price": lambda v: Span(f"${v:.2f}", cls="font-mono"),
    },
)

Extra Columns

Add computed columns (e.g., action buttons):

def render_actions(row):
    return Div(
        A("Edit", href=f"/items/{row.id}/edit", cls="btn btn-warning btn-xs"),
        ConfirmDelete("Delete", url=f"/items/{row.id}", cls="btn btn-error btn-xs"),
        cls="flex gap-1",
    )

DataGrid(
    Item,
    items,
    data_url="/items/_list",
    extra_columns={"Actions": render_actions},
)

Bulk Actions

DataGrid(
    Item,
    items,
    data_url="/items/_list",
    bulk_actions=[
        ("Delete Selected", "/items/_bulk_delete"),
        ("Export Selected", "/items/_export"),
    ],
)

Bulk action endpoints receive selected form values (list of IDs from checked rows).