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
| | | |
|---|
| | Stable identity for the table instance. | Present in the public struct, but the checked-in renderer does not currently consume it internally. |
| | Column definitions in display order. | Required. Width comes from the column records. |
| | Row data in display order. | Required. Each row's cells are matched to columns by index. |
| | Currently selected row ids. | |
| Option<Arc<dyn Fn(String) -> ActionEnvelope + Send + Sync>> | Closure that builds the action for row or checkbox selection. | |
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.