URL State Management
NEVER use raw useSearchParams — always use the dedicated hooks from frontend/src/hooks/url-state/.
Available Hooks
| Hook | Purpose | Example |
|---|---|---|
useTabState(validTabs, default) | Tab switching with URL sync | ?tab=details |
useFilterState(defaults) | Multi-param filter state | ?status=active&search=solar |
useModalState(param?) | Deep-linkable modal/dialog | ?modal=create |
useMultiSortState(columns, defaultSort) | Multi-column sort with Shift+Click stacking | ?sort=name.asc,date.desc |
All hooks are exported from frontend/src/hooks/url-state/index.ts.
Benefits
- Shareable URLs — copy/paste a filtered view to a colleague
- Browser navigation — back/forward buttons work with state changes
- Refresh survival — state persists across page reloads
- Bookmarkable — save specific filtered/sorted views
Usage Examples
// Tab management
const [activeTab, setActiveTab] = useTabState(['overview', 'details', 'files'], 'overview');
// Filter state with defaults
const [filters, setFilters] = useFilterState({
status: 'all',
search: '',
});Multi-Sort
useMultiSortState supports stacking sort columns via Shift+Click:
const [sort, toggleSort] = useMultiSortState(
['name', 'date', 'status'],
[{ column: 'date', direction: 'desc' }]
);Single click replaces the sort. Shift+Click adds a secondary sort column.
Testing
Tests live in frontend/src/hooks/url-state/__tests__/ covering all four hooks.
See Also
- State Management — when to use URL state vs alternatives
- Hooks — overall hook organization
- Frontend Architecture — routing and URL structure
- Component Decomposition — where URL hooks are called
- React Query Pattern — combining URL state with server queries