Pagination & URL State (nuqs)
Overview
Our data tables use URL-synchronized state via nuqs. Pagination should be stable: selecting rows or toggling non-paging controls must not reset the current page to 1. This guide explains:- How pagination parameters are modeled
- Which URL params trigger a page reset
- The
OMIT_FIELDSlist used to prevent unwanted resets - Practical recommendations when adding new URL params
Key URL Parameters
page: current page (1-based)size: page sizesort: sort field keyasc: sort direction (boolean)filter: whether filtering UI is enabled (boolean)- Additional dynamic filter params (e.g.,
doc_date,status, etc.) - Selection and UI-only params (e.g.,
selected)
Page Reset Rules
Changing actual filter values should reset to page 1 so users see results from the beginning. However, changes to purely presentational or ephemeral state (like selection) must not trigger a reset. We implement this using an omit list during change detection.OMIT_FIELDS
Source of truth in the webapp utility:page to the default.
Where Reset Happens
The reset to page 1 is applied inprocessSearchParams when a meaningful change is detected:
useQueryFiltersSync resets page when any filter group (not omitted) changes, using a debounced effect to avoid jitter during typing:
What Should Not Reset Pagination
The following changes must not reset the page:- Row selection changes:
selected - Sorting toggles:
sort,asc - Pagination controls themselves:
page,size - View toggles/tabs:
tab - UI-only flags that don’t change the dataset shape
OMIT_FIELDS or otherwise do not affect the reset logic.
What Should Reset Pagination
Any change that alters the dataset shape/order enough that page N might no longer contain the same items, for example:- Adding/removing/changing filter values (e.g.,
doc_date,status) - Toggling
filterthat enables filter mode and reveals active filters - Changing object scoping parameters
OMIT_FIELDS so that the system resets to page 1.
Best Practices When Adding Params
- Classify the parameter:
- Data-affecting (should reset) vs. UI-only/ephemeral (should not reset)
- If it should not reset, add its key to
OMIT_FIELDSinsearch-params-utils.ts. - Keep pagination stable on selection and sort changes.
- Debounce page resets on filter edits to avoid flicker.
- Keep URL key mapping consistent (see
search-params-configforpageSize⇄size).
Example: Row Selection Should Not Reset
In AR Reconciliation, selecting a row updates theselected query param. Because selected is listed in OMIT_FIELDS, changing selection will not reset page.
Troubleshooting
- Pagination resets unexpectedly: Verify the param is in
OMIT_FIELDSif it is UI-only. - Page doesn’t reset when filters change: Ensure those filter keys are NOT in
OMIT_FIELDSand that they flow throughprocessSearchParams. - Jumping during typing: Confirm debounce is applied in
useQueryFiltersSync.
By following these rules and maintaining
OMIT_FIELDS, pagination remains predictable while filters and controls work as expected.