bc-grid
GitHub

URL state

View source

Drive 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.replace so 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 useSearchParams consumers 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.