
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-url-query-params
Advanced tools
React hooks for managing and updating URL query parameters with batch updates and type safety.
A lightweight React hook library for managing URL query parameters with full TypeScript support and auto-generated helper methods.
Works with react-router-dom, Next.js App Router, and Next.js Pages Router — same API, just swap the import path.
| Import path | Router | When to use |
|---|---|---|
react-url-query-params | react-router-dom v6+ | CRA, Vite, Remix |
react-url-query-params/next | Next.js App Router (next/navigation) | Next.js 13+ with app/ directory |
react-url-query-params/next-pages | Next.js Pages Router (next/router) | Next.js with pages/ directory |
set<Key>, toggle<Key>, is<Key><Option>, clear<Key>npm install react-url-query-params
or
yarn add react-url-query-params
Components using hooks from react-url-query-params/next call useSearchParams() from next/navigation internally. Next.js requires these to be wrapped in a <Suspense> boundary:
import { Suspense } from ‘react’;
import MyComponent from ‘./MyComponent’;
export default function Page() {
return (
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
);
}
useUrlParams‘use client’;
import { useUrlParams } from ‘react-url-query-params/next’;
export default function MyComponent() {
const { view, setView, toggleView, clearView, isViewGrid, isViewTable } = useUrlParams({
keyName: ‘view’,
options: [‘grid’, ‘table’] as const,
});
return (
<div>
<p>Current view: {view}</p>
<button onClick={() => setView(‘grid’)}>Grid</button>
<button onClick={() => setView(‘table’)}>Table</button>
<button onClick={() => toggleView()}>Toggle</button>
<button onClick={() => clearView()}>Clear</button>
{/* Replace history entry instead of adding a new one */}
<button onClick={() => setView(‘grid’, { replace: true })}>Grid (No History)</button>
{isViewGrid && <div>Grid mode enabled</div>}
{isViewTable && <div>Table mode enabled</div>}
</div>
);
}
useBatchUrlParams‘use client’;
import { useBatchUrlParams } from ‘react-url-query-params/next’;
export default function FilterPanel() {
const { set, clearParams, isFilterActive, isSortDesc } = useBatchUrlParams({
filter: [‘active’, ‘inactive’] as const,
sort: [‘asc’, ‘desc’] as const,
});
return (
<div>
<button onClick={() => set({ filter: ‘active’, sort: ‘asc’ })}>Active + Asc</button>
<button onClick={() => set({ sort: ‘desc’ }, { replace: true })}>Desc (No History)</button>
<button onClick={() => clearParams()}>Clear all</button>
{isFilterActive && <span>Showing active</span>}
{isSortDesc && <span>Sorted descending</span>}
</div>
);
}
In the Pages Router, router.isReady is false on the first render during SSR/hydration. During this render all hook values return null and all boolean flags return false. The component re-renders automatically once the router is ready with real URL values.
useUrlParamsimport { useUrlParams } from ‘react-url-query-params/next-pages’;
export default function MyComponent() {
const { view, setView, toggleView, clearView, isViewGrid, isViewTable } = useUrlParams({
keyName: ‘view’,
options: [‘grid’, ‘table’] as const,
});
return (
<div>
<p>Current view: {view ?? ‘loading...’}</p>
<button onClick={() => setView(‘grid’)}>Grid</button>
<button onClick={() => setView(‘table’)}>Table</button>
<button onClick={() => toggleView()}>Toggle</button>
<button onClick={() => clearView()}>Clear</button>
{isViewGrid && <div>Grid mode enabled</div>}
{isViewTable && <div>Table mode enabled</div>}
</div>
);
}
useBatchUrlParamsimport { useBatchUrlParams } from ‘react-url-query-params/next-pages’;
export default function FilterPanel() {
const { set, clearParams, isFilterActive, isSortDesc } = useBatchUrlParams({
filter: [‘active’, ‘inactive’] as const,
sort: [‘asc’, ‘desc’] as const,
});
return (
<div>
<button onClick={() => set({ filter: ‘active’ })}>Active</button>
<button onClick={() => set({ sort: ‘desc’ }, { replace: true })}>Desc (No History)</button>
<button onClick={() => clearParams()}>Clear all</button>
{isFilterActive && <span>Showing active</span>}
</div>
);
}

useUrlParamsimport { useUrlParams } from 'react-url-query-params';
export default function MyComponent() {
const { view, setView, toggleView, clearView, isViewGrid, isViewTable } = useUrlParams({
keyName: 'view',
options: ['grid', 'table'],
});
return (
<div>
<p>Current view: {view}</p>
<button onClick={() => setView('grid')}>Grid</button>
<button onClick={() => setView('table')}>Table</button>
<button onClick={() => toggleView()}>Toggle</button>
<button onClick={() => clearView()}>Clear</button>
{/* Replace history entry instead of adding new one */}
<button onClick={() => setView('grid', { replace: true })}>
Grid (No History)
</button>
<button onClick={() => toggleView({ replace: true })}>
Toggle (No History)
</button>
{isViewGrid && <div>Grid mode enabled</div>}
{isViewTable && <div>Table mode enabled</div>}
</div>
);
}
useBulkUrlParamsimport { useBulkUrlParams } from 'react-url-query-params';
export default function MyComponent() {
const { set, isViewGrid, isViewTable, isModalOpened, isModalClosed } = useBulkUrlParams({
view: ['grid', 'table'],
modal: ['opened', 'closed'],
});
return (
<div>
<button onClick={() => set({ view: 'grid', modal: 'opened' })}>
Open Grid View
</button>
<button onClick={() => set({ view: 'table' })}>
Switch to Table
</button>
{isViewGrid && <div>Grid mode enabled</div>}
{isViewTable && <div>Table mode enabled</div>}
{isModalOpened && <div>Modal is open</div>}
{isModalClosed && <div>Modal is closed</div>}
</div>
);
}
useUrlParams(config)Manage a single query parameter with type-safe helpers.
Config:
| Option | Type | Description |
|---|---|---|
keyName | string | Query parameter key |
options | readonly string[] | Allowed values for this param |
Returns:
[keyName] — current value (string or null)set<Key> — function to set a value
{ replace: boolean } - Controls browser history behavior
replace: false (default) - Adds a new entry to browser historyreplace: true - Replaces the current history entrytoggle<Key> — toggle between 2 allowed values (only works if options.length === 2)
{ replace: boolean } - Controls browser history behaviorclear<Key> — function to clear parameter from url
{ replace: boolean } - Controls browser history behavioris<Key><Option> — boolean helper for quick checksExample:
const { view, setView, toggleView, clearView, isViewGrid, isViewTable } = useUrlParams({
keyName: 'view',
options: ['grid', 'table'],
});
// Basic usage
setView('grid');
toggleView();
clearView();
// Control browser history
setView('grid', { replace: true });
toggleView({ replace: true });
clearView({ replace: true });
useBulkUrlParams(config)Manage multiple query parameters simultaneously with a single hook.
Config:
A record object where:
'view', 'modal')['grid', 'table'])Returns:
set — function to update one or more parameters at once
{ replace: boolean } - Controls browser history behavior
replace: false (default) - Adds a new entry to browser historyreplace: true - Replaces the current history entryis<Key><Option> — boolean flags for each key-option combination
is${Capitalize<Key>}${Capitalize<Option>}view: ['grid', 'table'], you get isViewGrid and isViewTableExamples:
// Basic usage
const { set, isViewGrid, isViewTable, clearParams } = useBulkUrlParams({
view: ['grid', 'table'],
});
// Multiple parameters
const { set, isViewGrid, isViewTable, isModalOpened, isModalClosed, clearParams } = useBulkUrlParams({
view: ['grid', 'table'],
modal: ['opened', 'closed'],
});
// Update single parameter
set({ view: 'grid' });
// Update multiple parameters at once
set({ view: 'table', modal: 'opened' });
// Control browser history (replace current entry instead of adding new one)
set({ view: 'grid' }, { replace: true });
// Use boolean flags
if (isViewGrid && isModalOpened) {
// Both conditions are true
}
Advanced Example:
import { useBulkUrlParams } from 'react-url-query-params';
function FilterableTable() {
const { set, isSortAsc, isSortDesc, isFilterActive, isFilterInactive, clearParams } = useBulkUrlParams({
sort: ['asc', 'desc'],
filter: ['active', 'inactive'],
});
return (
<div>
<button onClick={() => set({ sort: 'asc' })}>
Sort Ascending {isSortAsc && '✓'}
</button>
<button onClick={() => set({ sort: 'desc' })}>
Sort Descending {isSortDesc && '✓'}
</button>
<button onClick={() => set({ filter: 'active' })}>
Show Active {isFilterActive && '✓'}
</button>
<button onClick={() => set({ filter: 'inactive' })}>
Show Inactive {isFilterInactive && '✓'}
</button>
{/* Update both at once */}
<button onClick={() => set({ sort: 'desc', filter: 'active' })}>
Reset Filters
</button>
{/* Replace history entry (no back button navigation) */}
<button onClick={() => set({ sort: 'asc' }, { replace: true })}>
Sort Asc (No History)
</button>
<button onClick={() => clearParams()}>
Clear all
</button>
</div>
);
}
Notes:
as const for the options arrays to get the best TypeScript inferenceclearParams function will clear all params declared in hookset function accepts an optional second parameter { replace: boolean } to control browser history:
replace: false (default) - Adds a new entry to browser history (users can use back button)replace: true - Replaces the current history entry (prevents back button navigation to previous state)Contributions are welcome! Please feel free to submit a Pull Request.
MIT © Pavlo Kuzina
FAQs
React hooks for managing and updating URL query parameters with batch updates and type safety.
We found that react-url-query-params demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.