URL state
View sourceDrive any controlled-state dimension from the URL with the standard React controlled-prop pair. The grid stays the source of truth for the runtime view; the URL is just one persistence target among many.
Try this
The bar above the grid shows the live URL query string. Watch it change as you interact.
- Type into the search input — URL gains
?q=acme. - Click a header to sort — URL gains
&sort=customer:asc. - Shift-click another header — URL becomes
&sort=customer:asc,amount:desc. - Refresh the page — the same view comes back. The URL is the source of truth.
- Copy the URL into a new tab — same grid view appears. Shareable.
The pattern
Every persistable dimension on BcGridProps ships as a controlled-prop triplet:
- value prop:
sort,filter,searchText,groupBy,selection,expansion… - change handler:
onSortChange,onFilterChange,onSearchTextChange… - defaultValue prop:
defaultSort,defaultFilter… for uncontrolled mode.
Pass the value + handler to round-trip through any source — URL, localStorage, Redux, server-synced view DTO.
Designing the URL schema
- Pick a stable serialization. The demo uses
?sort=col:dir,col:dir— short, human-readable, future-safe. JSON works too if you don't mind the noise. - Use replace, not push. Each interaction shouldn't add a history entry — use
router.replaceso back-button still does what users expect. - Drop falsy params. Empty search, no sort — remove the param entirely so the URL stays clean.
- Wrap in Suspense. Next.js requires
useSearchParamsconsumers to be wrapped in a Suspense boundary for static prerender. The demo's page does that around the demo component.
Combining persistence sources
You can mix: useBcGridState for everything that's session-private (column resize, density, sidebar panel) + sort / filter / searchText driven explicitly from the URL. The grid composes them: pass the URL-driven dimensions as overrides on the spread grid.props, and they win.