URL-synced UI State (modals, tabs, filters)
UI components like modals, side views, tabs, and filters must keep their state in sync with the URL's query parameters. This ensures that the application state is shareable, reproducible, and restorable. Copying the URL and opening it in another browser tab should reproduce the exact same UI.
Why this matters
- Shareability: A link to a page with specific filters or a modal open should reproduce the same view when shared.
- Reproducibility: QA and debugging become easier when testers can copy a failing state as a URL.
- Navigation consistency: Browser forward/back buttons work correctly when UI state is tied to the URL.
- SEO and analytics: Query params make significant UI states visible to crawlers and trackable for analytics.
Use cases
- Modals: Opening a modal (e.g., user details) must update the URL with something like
?modal=user&userId=123. Closing it removes those params. - Tabs: Active tab selection (e.g.,
overview,details,activity) should sync with?tab=details. Reloading or sharing the link restores the correct tab. - Filters: Complex filters (search term, status, sort order, pagination) should serialize into one query param (e.g.,
?filters=...). This allows filters to persist on reload or be shared with others. - Side views/drawers: Opening a side panel (e.g., a settings drawer) should toggle a query param like
?view=settings.
Implementation approach
- One centralized hook manages syncing state to query params. Components only consume and set state through this hook.
- The hook abstracts serialization (for objects like filters) and ensures consistent behavior across the system.
- The hook uses
router.replaceinternally to avoid spamming the browser history with every state change.
Common pitfalls if not followed
- Lost state on reload: If state only lives in memory, refreshing resets the UI.
- Broken shareability: QA, product managers, or users cannot share a URL that reproduces what they see.
- Inconsistent navigation: Browser back/forward buttons don't reflect UI changes like closing a modal or switching a tab.
- Duplicate implementations: Without a central hook, each component manipulates
window.locationdifferently, leading to bugs and inconsistencies. - Harder debugging: Developers cannot reproduce issues from a link since the state isn't encoded in the URL.