# Table Pattern

The canonical working example is `src/sections/records/view/records-list-view.tsx`. Its data is local, but its props intentionally match a server-driven list.

## Included behavior

- Debounced quick search
- Server-shaped pagination and primary/advanced filters
- Current-page multi-column filters, including dates
- Client sort, column visibility and drag reorder
- Comfortable, compact, and dense rows
- Sticky header preference
- Selection and bulk-action slot
- CSV export, print, refresh, empty/loading/error states
- Persistent table preferences via `storageKey`

## API migration

Replace the local state and `filteredRows/pageRows` calculation with:

```tsx
const list = usePaginatedList<MyRow>(endpoints.records.root, urlFilters);

<DataTable
  columns={columns}
  rows={list.rows}
  total={list.total}
  page={list.page}
  rowsPerPage={list.rowsPerPage}
  search={list.search}
  loading={list.isLoading}
  searching={list.isSearchPending || list.isValidating}
  error={Boolean(list.error)}
  onChangePage={(page) => list.onPaginationModelChange({ page, pageSize: list.rowsPerPage })}
  onChangeRowsPerPage={(pageSize) => list.onPaginationModelChange({ page: 0, pageSize })}
  onChangeSearch={list.onSearch}
/>
```

Keep API filters separate from the DataTable's current-page filter panel. Fetch stable option lists once with `useFilterOptions`; do not refetch them with every page change.
