Server data table
Search, filter and page through records the server holds, with debounced requests, cancellation, skeletons and "Load more".
The data table pattern filters rows it already has. When the server holds more than you want to load at once, the server searches and pages instead. This is the markup and behaviour to copy, as components/<thing>-table.tsx.
| Person | Role | Scope | Status |
|---|---|---|---|
0 shown
How it's built
| Part | Built with |
|---|---|
| Search | InputGroup; the query is debounced (250 ms) before it's sent, and a Spinner shows in the field while a new search runs over old rows |
| Filters | Toggle variant="outline" for on/off filters ("Show revoked"); a Select for a choice of several |
| Cancelling | Every request gets an AbortController; a new query aborts the one in flight, so old answers never overwrite new ones |
| First load | Skeleton rows the same height as real ones |
| Refreshing | The old rows stay, dimmed, until the new page arrives; aria-busy on the table |
| Paging | Cursor paging: the server returns nextCursor, "Load more" appends the next page. The count says how many are shown, not a total the server didn't compute |
| Errors | Alert destructive above the table, saying what to do next; rows already loaded stay |
| People | Person in cells, never raw IDs |
| No results | Empty across all columns, quoting the query |
Cursor or page numbers
- Cursor ("Load more") when rows are added often (logs, assignments) or counting is expensive. Pages never shift under people, and the server stays fast.
- Page numbers (Previous and Next with "Page 2 of 9") when people need to jump or share a position. That needs a total count from the server.
Either way, keep the query, filters and position in the URL (?q=kasun&revoked=1), so the back button and a shared link restore the view.
Guidelines
- Never filter server data on the client as well; people will think the server found nothing.
- Don't clear rows to show a spinner on each keystroke. Keep them and dim them.
- Reset to the first page whenever the query or a filter changes.
- Everything from the data table guidelines applies: no brand in the table, a border not a card, five to seven columns.