DataTable
OrganismTable + SearchBar + Pagination in a single component. Client-side search and pagination with filtered result counter and rows-per-page selector. rowActions adds a per-row actions menu (id, label, onClick or href, hidden, disabled, disabledReason, destructive, group, order).
Users
87 total
| Name | Role | Status | Joined |
|---|---|---|---|
| Alice Johnson | Admin | Active | Jan 2024 |
| Bob Smith | Editor | Active | Mar 2024 |
| Carol White | Viewer | Inactive | Jun 2024 |
| Dan Brown | Editor | Pending | Sep 2024 |
Showing 1–20 of 87
<%- include('modules/ui/DataTable', {
title: 'Users',
subtitle: total + ' total',
columns: [
{ key: 'name', header: 'Name' },
{ key: 'role', header: 'Role' },
{ key: 'status', header: 'Status' },
{ key: 'joined', header: 'Joined', align: 'right' },
],
rows: users,
page: page, // current page (1-based), from req.query
total: total, // total record count, from DB
pageSize: 20,
qs: qs, // query string without 'page', from route
}) %>
<%-- In your Express route: --%>
<%
// const page = parseInt(req.query.page) || 1;
// const { users, total } = await UserService.list({ page, pageSize: 20 });
// const qs = new URLSearchParams(req.query); qs.delete('page');
// res.render('users/index', { users, total, page, qs: qs.toString() });
%>
Users
| Name | Role | Status | Joined |
|---|---|---|---|
| Alice Johnson | Admin | Active | Jan 2024 |
| Bob Smith | Editor | Active | Mar 2024 |
| Carol White | Viewer | Inactive | Jun 2024 |
| Dan Brown | Editor | Pending | Sep 2024 |
Showing 1–4 of 4
<%- include('modules/ui/DataTable', {
columns: [...],
rows: users,
page: page,
total: total,
pageSize: 20,
qs: qs,
getRowHref: function(row) { return '/users/' + row.userId; }
}) %>
| Name | Role | Status | Joined |
|---|---|---|---|
| Alice Johnson | Admin | Active | Jan 2024 |
| Bob Smith | Editor | Active | Mar 2024 |
| Carol White | Viewer | Inactive | Jun 2024 |
| Dan Brown | Editor | Pending | Sep 2024 |
Showing 1–4 of 4
<%- include('modules/ui/DataTable', {
columns: [
{ key: 'name', header: 'User',
render: function(row) {
return '<div class="flex items-center gap-2">'
+ '<span class="h-7 w-7 rounded-full bg-primary-subtle text-primary text-xs flex items-center justify-center">'
+ row.name.charAt(0).toUpperCase()
+ '</span>'
+ '<span class="font-medium text-text-primary">' + row.name + '</span>'
+ '</div>';
}
},
{ key: 'status', header: 'Status',
render: function(row) {
var v = row.status === 'Active' ? 'bg-success-subtle text-success-fg'
: row.status === 'Pending' ? 'bg-warning-subtle text-warning-fg'
: 'bg-surface-overlay text-text-secondary';
return '<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ' + v + '">'
+ row.status + '</span>';
}
},
],
rows: users,
page: page,
total: total,
pageSize: 20,
qs: qs,
}) %>
Users
| Name | Role | Status | Joined |
|---|---|---|---|
| No users found. | |||
Showing 0–0 of 0
<%- include('modules/ui/DataTable', {
columns: [...],
rows: [],
page: 1,
total: 0,
pageSize: 20,
qs: qs,
emptyMessage: 'No users found.'
}) %>
| Company | Status | Actions | |
|---|---|---|---|
| Northwind Traders | buy@northwind.example | Active |
|
| Contoso Ltd | — | Active |
|
| Fabrikam | info@fabrikam.example | Archived |
|
<%# A trailing column with one menu per row. Every per-row field takes a function of the row. %>
<%- include('modules/ui/DataTable', {
rows: companies,
columns: columns,
rowActionsLabel: function (row) { return 'Actions for ' + row.name; },
rowActions: [
{ id: 'open', label: 'Open', href: function (row) { return '/companies/' + row.id; } },
{ id: 'call', label: 'Call', group: 'contact', order: 10, onClick: function (row) { return "callCompany('" + row.id + "')"; } },
{ id: 'sign', label: 'Send for signature', group: 'contact', order: 20,
disabled: function (row) { return !row.email; }, disabledReason: 'Add an email address first' },
{ id: 'restore', label: 'Restore', hidden: function (row) { return row.status !== 'Archived'; } },
{ id: 'delete', label: 'Delete', group: 'danger', order: 1000, destructive: true },
]
}) %>
<%# Backwards-compatible shim — `DataTable` now lives in `modules/ui/Table/`.
Defaults to `mode="paginated"` so existing consumers see no behavioral
change. Use the new modes (`static` | `server`) via the unified
`include('modules/ui/Table/Table', { mode: '…' })` API. %>
<%- include('./Table/Table', Object.assign({}, locals, { mode: locals.mode || 'paginated' })) %>