Data Table¶
Building sortable, filterable data tables in Rezi.
Problem¶
You need to display tabular data with sorting and filtering capabilities.
Solution¶
Use the built-in ui.table widget, and keep sort/filter state in your app state.
Complete Example¶
import { createApp, ui } from "@rezi-ui/core";
import { createNodeBackend } from "@rezi-ui/node";
type User = { id: string; name: string; email: string; role: string };
type SortDirection = "asc" | "desc";
type State = {
users: User[];
sort: { column: string; direction: SortDirection };
filter: string;
selection: string[];
};
function filterUsers(users: User[], filter: string): User[] {
if (!filter) return users;
const lower = filter.toLowerCase();
return users.filter(
(u) => u.name.toLowerCase().includes(lower) || u.email.toLowerCase().includes(lower)
);
}
const app = createApp<State>({
backend: createNodeBackend(),
initialState: {
users: [
{ id: "1", name: "Ada", email: "ada@example.com", role: "Admin" },
{ id: "2", name: "Linus", email: "linus@example.com", role: "User" },
{ id: "3", name: "Grace", email: "grace@example.com", role: "User" },
],
sort: { column: "name", direction: "asc" },
filter: "",
selection: [],
},
});
app.view((state) => {
const filtered = filterUsers(state.users, state.filter);
return ui.column({ flex: 1, gap: 1, p: 1 }, [
ui.row({ gap: 1 }, [
ui.text("Search:"),
ui.input({
id: "filter",
value: state.filter,
onInput: (value) => app.update((s) => ({ ...s, filter: value })),
}),
]),
ui.table({
id: "users",
data: filtered,
getRowKey: (u) => u.id,
columns: [
{ key: "name", header: "Name", flex: 1, sortable: true },
{ key: "email", header: "Email", flex: 2, sortable: true },
{ key: "role", header: "Role", width: 10, sortable: true },
],
selectionMode: "multi",
selection: state.selection,
onSelectionChange: (keys) => app.update((s) => ({ ...s, selection: [...keys] })),
sortColumn: state.sort.column,
sortDirection: state.sort.direction,
onSort: (column, direction) => app.update((s) => ({ ...s, sort: { column, direction } })),
stripedRows: true,
}),
]);
});
app.keys({ q: () => app.stop(), "ctrl+c": () => app.stop() });
await app.start();
Explanation¶
- Filter state is kept in
state.filterand applied before passing data to the table. - Sorting is handled by the table (it emits
onSort(column, direction)and you store that in state). - Selection is stored as row keys and updated via
onSelectionChange.
Related¶
- Divider - Table separators
- Loading States - Async data loading