Add URL sync
Add URL sync when the URL is part of the product surface, not just a convenient way to share a one-off state.
This is the right tool for pages where people expect refresh, back/forward navigation, or a pasted URL to preserve the active query state.
When to use URL sync
Use continuous URL sync when people need to:
- reload the page and keep the same search, filters, sorting, or grouping
- use back and forward navigation as part of the table workflow
- bookmark a live working state
- treat table state as part of the page's contract
Do not reach for it by default.
For many product tables, persistState plus copyLink is a better fit because it keeps the address bar stable during normal interaction.
Turn on URL sync
<Datatable
tableKey="customers"
data={rows}
columns={columns}
getRowId={(row) => row.id}
urlSync={{
enabled: true,
acceptUrlParams: true,
historyMode: "replace",
}}
/>The table reads URL state during initialization, merges it through the table-state coordinator, and then enables continuous store-to-URL sync after it is ready.
History behavior
historyMode controls how state changes affect browser navigation.
- Use
"replace"when the page should reflect the latest state without creating a long back-stack trail. - Use
"push"when stepping backward through prior table states is a real product behavior.
If you are unsure, start with "replace".
What URL sync includes
URL sync serializes the shareable query state of the table:
- global search (
q) - column filters (
f.columnId) - sorting (
s) - filter mode (
fm) - grouping (
g)
It does not serialize personal layout preferences such as column visibility, widths, order, sticky columns, or the active saved-view ID.
Those belong in persistence and saved-view systems instead.
Initialization priority
URL state has the highest priority during initialization.
A URL-synced state can override:
- default store state
- persisted per-user state
initialState- saved default views
- current-view persistence
That precedence makes pasted links and bookmarks reliable.
One-load URL params
If the page should accept shared URLs but should not keep mutating the address bar after load, use this pattern instead:
<Datatable
tableKey="customers"
data={rows}
columns={columns}
getRowId={(row) => row.id}
urlSync={{
enabled: false,
acceptUrlParams: true,
}}
toolbar={{ copyLink: true }}
/>In that mode, the table reads the incoming URL state once, applies it, and clears the datatable params afterward.
That is usually better for product tables where the address bar should stay clean but shared links should still work.
Long filter states
The URL writer uses the table's canonical filter encoding:
- text and number filters use their condition mode names
- date filters use
preset,range,before,after, andcustom - list filters use
includeandexclude
Continuous URL sync works best when filters are reasonably compact and the page is not trying to encode large custom payloads into the URL.
If users routinely build large states, guide them toward saved views instead.
Multi-table pages
Only one table on a page should run with urlSync.enabled: true.
The current implementation uses shared parameter names like q, s, and f.columnId, so multiple live URL-synced tables on the same page will collide.
If a page needs multiple tables, keep continuous URL sync on just one of them or avoid the feature entirely until namespacing exists.
Verify production behavior
Before shipping URL sync, verify that:
- opening a bookmarked or pasted URL restores the expected query state
- browser back and forward navigation match the chosen
historyMode - URL state overrides persisted state on first load
- the page still behaves correctly when the URL contains no datatable params
- overly large states fail safely and have a saved-view fallback in product guidance
Keep the mental model simple for users
The easiest product framing is:
- Persistence remembers my setup
- Saved views give names to reusable setups
- Copy links share a snapshot on demand
- URL sync makes the address bar part of the live table experience
If the page does not need that last promise, do not force it.