DataTable

DataTable is the basic tabular-data widget in the authoring set.
Use it when users need to scan rows against shared columns: files, users, invoices, runs, and similar structured records. A table solves a different problem than a list or card grid. It trades visual warmth for fast comparison across fields.

Example

use fission::prelude::*;
use std::sync::Arc;

let widget: Widget = DataTable {
    id: WidgetId::explicit("build_runs_table"),
    columns: vec![
        TableColumn {
            id: "status".into(),
            title: "Status".into(),
            width: 120.0,
            sortable: false,
        },
        TableColumn {
            id: "branch".into(),
            title: "Branch".into(),
            width: 180.0,
            sortable: true,
        },
    ],
    rows: vec![
        TableRow {
            id: "run_42".into(),
            cells: vec!["Passed".into(), "main".into()],
        },
    ],
    selected_ids: view.state().selected_run_ids.clone(),
    on_selection_change: Some(Arc::new(move |row_id| ActionEnvelope {
        id: toggle_row_selection_id,
        payload: serde_json::to_vec(&ToggleRowSelection(row_id)).unwrap(),
    })),
}
.into();
Here the table is responsible for presentation. The reducer is responsible for which rows are selected and what selection means.

Field table

Field
Type
Meaning
Notes / default behavior
id
WidgetId
Stable identity for the table instance.
Present in the public struct, but the checked-in renderer does not currently consume it internally.
columns
Vec<TableColumn>
Column definitions in display order.
Required. Width comes from the column records.
rows
Vec<TableRow>
Row data in display order.
Required. Each row's cells are matched to columns by index.
selected_ids
Vec<String>
Currently selected row ids.
Controlled by app state.
on_selection_change
Option<Arc<dyn Fn(String) -> ActionEnvelope + Send + Sync>>
Closure that builds the action for row or checkbox selection.
Called with the row id.

How to think about tabular data here

A table works when every row shares the same shape and when columns matter more than custom per-row layout. The checked-in DataTable is intentionally simple: cells are plain strings, not arbitrary widgets. That keeps comparison easy, but it also means complex media cells, nested controls, or heavily formatted content usually want a custom table layout instead.
Selection is explicit. The widget highlights rows whose ids appear in selected_ids, and it uses the same selection callback for row presses and row checkboxes.

Current behavior and limits

Two implementation details matter today. First, the header's select-all checkbox is currently visual only. Second, TableColumn.sortable currently adds a sort indicator but no built-in sorting callback. In other words, the widget presents table affordances, but your app still owns all real sorting and bulk-selection behavior.

Specific advice

Keep column counts modest on narrow screens. If comparison is still important on mobile, consider a smaller table with fewer columns plus a drill-in detail view instead of forcing a huge horizontal matrix.

Production checklist

For DataTable, review the fields that change behavior before treating the widget as finished: id, columns, rows, selected_ids, on_selection_change. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
Bind on_selection_change to explicit reducer actions and test that the reducer handles unavailable, duplicate, or invalid input safely.
Set id only when identity must be stable across filtering, reordering, diagnostics, or tests; otherwise let Fission derive identity from structure.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same DataTable setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
TableColumn, TableRow, Pagination, and Scroll.
Fission
A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.
Copyright (c) 2026 Fission
Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.
Fission 0.7.0