### Install All Dependencies
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md
Run this command in the root folder to install all project dependencies and perform other required setup steps.
```bash
npm run install:all
```
--------------------------------
### Run Development Mode
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Start the library in Rollup watch mode and run all example applications. The Next.js 15 demo is available at http://localhost:3000.
```bash
pnpm run dev
```
--------------------------------
### Install state-in-url Package
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
Install the state-in-url package using npm, yarn, or pnpm.
```sh
# npm
npm install --save state-in-url
# yarn
yarn add state-in-url
# pnpm
pnpm add state-in-url
```
--------------------------------
### Run Demo Project in Watch Mode
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md
Starts the demo project in watch mode for development. Ensure Playwright is installed separately.
```bash
npm run dev
```
--------------------------------
### Setup Playwright Dependencies
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Install Playwright with necessary dependencies, typically required before running end-to-end tests on a new machine.
```bash
pnpm run setup
```
--------------------------------
### Install AI Coding Agent Skills for state-in-url
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
Run this command to install skill files for AI coding agents to better understand and use the state-in-url library.
```sh
npx @tanstack/intent@latest install
```
--------------------------------
### useUrlEncode Hook Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useUrlEncode/README.md
Demonstrates how to use the useUrlEncode hook to get stringify and parse functions for managing URL state. Includes examples of stringifying state to a query string and parsing a query string back into a state object.
```typescript
import { useUrlEncode } from 'state-in-url/useUrlEncode';
const form = { name: '' };
const { parse, stringify } = useUrlEncode(form);
// Stringify state to URL query string
const queryString = stringify({ name: 'John' }, 'someExistingParamToKeep=123');
console.log(queryString); // Output: name='John'&someExistingParamToKeep=123
// Parse URL query string to state object
const state = parse("name='Tom'");
console.log(state); // Output: { name: 'Tom' }
```
--------------------------------
### Install state-in-url Package
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs15/public/llms.txt
Install the state-in-url package using npm. Ensure your tsconfig.json has moduleResolution set to 'Bundler', 'Node16', or 'NodeNext'.
```bash
npm install state-in-url
```
--------------------------------
### Basic useSharedState Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useSharedState.md
Demonstrates how to use useSharedState for state synchronization between components. Components referencing the same module-level state object will automatically sync.
```typescript
import { useSharedState } from 'state-in-url';
// Module level
const userState = { name: '', email: '', theme: 'light' };
// Component A
function SettingsPanel() {
const { state, setState } = useSharedState(userState);
return (
);
}
```
--------------------------------
### Filter Form Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-next.md
Demonstrates managing form state, including search queries, categories, and pagination, synchronized with the URL. It shows immediate state updates and debounced URL synchronization.
```typescript
import { useUrlState } from 'state-in-url/next';
const filterState = {
query: '',
category: 'all',
sort: 'recent',
page: 1,
};
type FilterState = typeof filterState;
export default function SearchPage() {
const { urlState, setState, setUrl, reset } = useUrlState(filterState, {
replace: true,
scroll: false,
});
const handleQueryChange = (e) => {
const query = e.target.value;
// Immediate state update
setState({ query, page: 1 });
// Debounced URL sync (waits 70ms for more changes)
setUrl({ query, page: 1 });
};
const handleCategoryChange = (cat) => {
setUrl({ category: cat, page: 1 });
};
const handleNextPage = () => {
setUrl((curr) => ({ ...curr, page: curr.page + 1 }));
};
return (
Showing page {urlState.page} sorted by {urlState.sort}
);
}
```
--------------------------------
### Debounce Timeout Behavior Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md
Illustrates the 'last update wins' semantics of the debounce mechanism, showing how rapid sequential updates result in a single URL write after a period of inactivity.
```text
User types: 't' → 'te' → 'tex' → 'tex ' → 'text'
Timeline (normal browser, 70ms timeout):
t: [ Timer starts ▲ ]
te: [ Timer cleared and restarted ▲ ]
tex: [ Timer cleared and restarted ▲ ]
tex : [ Timer cleared and restarted ▲ ]
text: [ Timer cleared and restarted ▲ ]
[ 70ms passes with no input ]
[ URL written to history once ✓ ]
```
--------------------------------
### Tabs with URL State Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md
Manages the active tab state and expansion status, synchronizing it with the URL. This allows users to bookmark or share specific tab views.
```typescript
const tabState = {
activeTab: 'overview',
expanded: false,
};
export function TabComponent() {
const { urlState, setUrl } = useUrlState(tabState, {
preventScrollReset: true,
});
return (
);
}
```
--------------------------------
### useUrlState Hook for Remix.js Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
Example demonstrating the usage of the useUrlState hook specifically for applications built with Remix.js. This hook integrates with Remix's routing and data loading mechanisms.
```typescript
import { useUrlState } from 'state-in-url';
interface RemixState {
filter: string;
}
const initialRemixState: RemixState = {
filter: '',
};
function RemixComponent() {
const [state] = useUrlState(initialRemixState);
return (
setUrlState({ filter: e.target.value })}
placeholder="Filter items..."
/>
{/* Render filtered items based on state.filter */}
);
}
```
--------------------------------
### Import useUrlState for Next.js
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/README.md
Quick start import for using `useUrlState` hook specifically within a Next.js application.
```typescript
import { useUrlState } from 'state-in-url/next';
```
--------------------------------
### Example of a Large State Object within Limits
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md
Illustrates a state object that fits comfortably within typical browser URL length limits. This example assumes approximately 60 bytes per field, resulting in a total state size well under the estimated 5000 character safe limit.
```typescript
// A state object with ~50 properties fits comfortably
const largeState = {
// 50 × ~60 byte fields = ~3000 bytes = ~3KB
// Comfortably under 5000 char safe limit
};
```
--------------------------------
### Browser History Integration Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md
Illustrates the automatic synchronization of component state with URL changes triggered by browser history events like the back/forward buttons.
```typescript
// User clicks back button
// → Browser navigates to previous URL
// → Hook receives popstate event
// → state updates to match URL
// → Component rerenders with new state
```
--------------------------------
### isEqual Utility Function Examples
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md
Shows examples of deep equality comparison using the isEqual function, which handles structural equality for objects and arrays, and type-aware comparison for primitives.
```typescript
isEqual({ a: 1 }, { a: 1 }); // true
isEqual([1, 2], [1, 2]); // true
isEqual(new Date('2024-01-15'), new Date('2024-01-15')); // true
isEqual({ a: [1, 2] }, { a: [1, 2] }); // true
```
--------------------------------
### Decoding Example with Symbols
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md
Illustrates how the reviver function decodes prefixed strings back into their original types, such as Date objects and undefined values.
```typescript
'⏲2024-01-15T00:00:00.000Z' → new Date('2024-01-15')
'∙undefined' → undefined
'hello' → 'hello' (unchanged)
```
--------------------------------
### setState Usage Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md
Demonstrates how to use the setState function to update the state locally without immediately synchronizing it to the URL. This is useful for responsive UI updates while debouncing URL changes.
```javascript
setState({ page: 2 }) // merge with current state
setState((curr, initial) => ({ ...curr, sort: 'asc' })) // updater function
```
--------------------------------
### Using routerHistory with useUrlStateBase
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/utilities.md
Demonstrates how to integrate `routerHistory` with the `useUrlStateBase` hook to manage application state synchronized with the URL. This example shows updating the URL to reflect a new page number.
```typescript
import { routerHistory, useUrlStateBase } from 'state-in-url';
const state = { search: '', page: 1 };
// Use routerHistory with useUrlStateBase
const { updateUrl } = useUrlStateBase(state, routerHistory);
updateUrl({ page: 2 }); // Uses window.history.replaceState
```
--------------------------------
### Full State Encoding Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md
Demonstrates encoding a state object containing various data types, including a Date and an undefined value, using the library's encode function and type symbols.
```typescript
import { SYMBOLS, encode } from 'state-in-url/encoder';
const state = {
name: 'John',
joined: new Date('2024-01-15'),
notes: undefined,
};
const encoded = encode(state);
// Result: '{"name":"John","joined":"⏲2024-01-15T00:00:00.000Z","notes":"∙undefined"}'
// Can be placed in URL:
// https://example.com?state={"name":"John","joined":"⏲2024-01-15T00:00:00.000Z","notes":"∙undefined"}
```
--------------------------------
### Creating a Custom useUrlState Hook
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useUrlStateBase/README.md
This example demonstrates how to create a custom useUrlState hook by extending the useUrlStateBase hook. It sets up a basic router object using React.useMemo for push and replace functionalities.
```typescript
import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
function useUrlStateCustom(state: T) {
const router = React.useMemo({
push: (url: string) => window.history.pushState(url),
replace: (url: string) => window.history.replaceState(url)
}, []);
return useUrlState(state, router);
}
```
--------------------------------
### Basic Usage of useUrlState Hook
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/react-router6/useUrlState/README.md
Demonstrates how to initialize the hook with default state, update state locally using setState, and update both state and URL using setUrl. Includes examples of functional updates and passing navigation options.
```typescript
import { useUrlState } from 'state-in-url/react-router6';
const form = { name: '', age: 0 };
const { urlState, setState, setUrl } = useUrlState(form);
// Update state without changing URL
setState({ name: 'test' });
setState(currVal => ({ ...currVal, name: 'test' }) );
// reset state
setState((_curr, initial) => initial);
// Update state and URL
// options from type `NavigateOptions` from 'react-router`
setUrl({ name: 'test' }, { replace: false, preventScrollReset: false });
// reset state and URL
setUrl((_curr, initial) => initial);
```
--------------------------------
### Undefined Value Encoding Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md
Shows how undefined values are encoded as the literal string '∙undefined'.
```typescript
undefined → '∙undefined'
```
--------------------------------
### Product Filtering Component with useUrlState
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-remix.md
Demonstrates how to use useUrlState to manage filter states for a product gallery. It includes examples for updating individual filters and resetting all filters. Options like 'replace' and 'preventScrollReset' can be configured.
```typescript
import { useUrlState } from 'state-in-url/remix';
const productFilters = {
query: '',
category: 'all',
priceMin: 0,
priceMax: 1000,
inStock: false,
page: 1,
};
export function ProductGallery() {
const { urlState, setState, setUrl, reset } = useUrlState(
productFilters,
{
replace: true,
preventScrollReset: true,
}
);
const handleSearch = (query) => {
setState({ query, page: 1 });
setUrl({ query, page: 1 });
};
const handlePriceRange = (min, max) => {
setUrl({ priceMin: min, priceMax: max, page: 1 });
};
const toggleStock = () => {
setUrl((curr) => ({ ...curr, inStock: !curr.inStock, page: 1 }));
};
return (
);
}
```
--------------------------------
### typeOf Utility Function Examples
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md
Demonstrates the detailed type information returned by the typeOf function, distinguishing between various types including null, arrays, objects, dates, and primitives.
```typescript
typeOf(null); // 'null'
typeOf([1, 2, 3]); // 'array'
typeOf({}); // 'object'
typeOf(new Date()); // 'date'
typeOf(42); // 'number'
typeOf(undefined); // 'undefined'
typeof undefined; // 'object' (difference!)
```
--------------------------------
### useSharedState with Initialization Function
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useSharedState.md
Utilize the optional initialization function to provide an initial state, for example, by loading data from localStorage. This function is called only once on the first browser mount.
```typescript
const userState = { name: '', age: 0 };
function Component() {
const { state, setState } = useSharedState(userState, () => {
// Called once on first browser mount
// Return initial state (e.g., from localStorage)
const saved = localStorage.getItem('user');
return saved ? JSON.JSON.parse(saved) : userState;
});
}
```
--------------------------------
### Using useUrlState Hook in Remix
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/remix/useUrlState/README.md
Demonstrates how to use the useUrlState hook to manage local component state synchronized with URL search parameters. Includes examples for updating state locally and updating both state and URL.
```typescript
import { useUrlState } from 'state-in-url/remix';
const form = { name: '', age: 0 };
const { urlState, setState, setUrl } = useUrlState(form);
// Update state without changing URL
setState({ name: 'test' });
setState(currVal => ({ ...currVal, name: 'test' }) );
// reset state
setState((_curr, initial) => initial);
// Update state and URL
// options from type `NavigateOptions` from 'react-router`
setUrl({ name: 'test' }, { replace: false, preventScrollReset: false });
// reset state and URL
setUrl((_curr, initial) => initial);
```
--------------------------------
### Using useUrlState in Layout with Middleware Workaround
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
This example demonstrates a workaround for accessing search parameters in Next.js App Router layouts using middleware to set headers. This allows the layout component to access and decode state from the URL.
```typescript
// add to appropriate `layout.tsc`
export const runtime = 'edge';
// middleware.ts
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const url = request.url?.includes('_next') ? null : request.url;
const sp = url?.split?.('?')?.[1] || '';
const response = NextResponse.next();
if (url !== null) {
response.headers.set('searchParams', sp);
}
return response;
}
// Target layout component
import { headers } from 'next/headers';
import { decodeState } from 'state-in-url/encodeState';
export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
const sp = headers().get('searchParams') || '';
return (
{children}
);
}
```
--------------------------------
### React Router v7 Setup with useUrlState
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/react-router-remix-setup/SKILL.md
Import and use the useUrlState hook from 'state-in-url/react-router' for React Router v7. Define your state type and initial state, then use the hook to access and update URL-bound state.
```typescript
import { useUrlState } from 'state-in-url/react-router';
type FiltersState = { sort: 'name' | 'date'; page: number };
const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
export function FiltersBar() {
const { urlState, setUrl } = useUrlState(FILTERS_STATE);
return ;
}
```
--------------------------------
### Using useUrlState in Remix Client Components
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-remix.md
Explains how to use useUrlState within Remix applications, emphasizing that hooks can only be used in Client Components. This example shows a common pattern where a Server Component renders a Client Component that utilizes the hook.
```typescript
// routes/search.tsx
export default function SearchPage() {
// This is a Server Component
// useUrlState cannot be used here
return ;
}
// routes/search.client.tsx or wrap in
import { useUrlState } from 'state-in-url/remix';
const searchForm = { query: '', page: 1 };
function SearchClient() {
// This must be a Client Component to use hooks
const { urlState, setUrl } = useUrlState(searchForm);
return (
setUrl({ query: e.target.value, page: 1 })}
/>
);
}
```
--------------------------------
### Using URL State Hook with History Enabled (Default)
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/nextjs-ssr/SKILL.md
This example shows the correct usage of the `useUrlState` hook with default history enabled. This is suitable for most cases where URL changes should update the browser history and avoid unnecessary server round-trips.
```typescript
useUrlState(FORM_STATE, { searchParams });
```
--------------------------------
### Cleanup and Reinstall
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Remove build artifacts and node_modules directories, then reinstall dependencies.
```bash
pnpm run cleanup
```
```bash
pnpm run reinstall
```
--------------------------------
### useUrlState Hook with Server-Side Rendering
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
Example of using the useUrlState hook in a server-side rendering context, likely within a Next.js application. Ensure proper setup for SSR compatibility.
```typescript
import { useUrlState } from 'state-in-url';
interface State {
userId: string;
}
const initialState: State = {
userId: '',
};
// Assume this is a Server Component or a component within Next.js SSR context
function UserProfile() {
const [state] = useUrlState(initialState);
return (
User Profile
User ID: {state.userId}
{/* Other profile details */}
);
}
```
--------------------------------
### Server-Side Initialization with useUrlStateBase
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlStateBase.md
Shows how to initialize state from the server using useUrlStateBase. It returns default values on the server and parses the URL on the client.
```typescript
const {
state,
updateUrl,
} = useUrlStateBase(
defaultForm,
router,
({ parse }) => {
// Called on first render in browser
if (typeof window === 'undefined') {
return defaultForm; // SSR
}
// Load from current URL or localStorage
const fromUrl = parse(window.location.search.slice(1));
return fromUrl;
},
);
```
--------------------------------
### decodePrimitive(str)
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/encoder.md
Restores type information from sentinel-prefixed strings. It decodes strings starting with '∙undefined' to undefined and strings starting with '⏲' to Date objects.
```APIDOC
## decodePrimitive(str)
### Description
Restores type information from sentinel-prefixed strings.
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Method
Not Applicable (Function Call)
### Endpoint
Not Applicable (Function Call)
### Parameters
- **str** (string) - Required - String to decode.
### Behavior
- Strings starting with `∙undefined` return `undefined`
- Strings starting with `⏲` are parsed as ISO date strings into Date objects
- All other strings are returned unchanged
### Example
```typescript
decodePrimitive('∙undefined'); // undefined
decodePrimitive('⏲2024-01-15T00:00:00.000Z'); // Date object
decodePrimitive('hello'); // 'hello'
```
### Source
`packages/urlstate/encoder/encoder.ts:107-112`
```
--------------------------------
### Build Library
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Build the library using Rollup, generating ESM, CJS, and .d.ts files in the dist/ directory.
```bash
pnpm run build
```
--------------------------------
### useUrlState Hook for React-Router Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
An example showcasing the use of the useUrlState hook within an application managed by React-Router. This allows URL state synchronization with React Router's navigation.
```typescript
import { useUrlState } from 'state-in-url';
import { useLocation, useNavigate } from 'react-router-dom';
interface RouterState {
page: number;
}
const initialRouterState: RouterState = {
page: 1,
};
function PaginationComponent() {
const location = useLocation();
const navigate = useNavigate();
// Pass location and navigate to useUrlState for React-Router integration
const [state] = useUrlState(initialRouterState, {
location,
navigate,
});
return (
Current Page: {state.page}
);
}
```
--------------------------------
### Using useUrlState Hook
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/react-router/useUrlState/README.md
Demonstrates how to initialize the useUrlState hook with default form values and how to use setState and setUrl to manage state and URL synchronization.
```typescript
import { useUrlState } from 'state-in-url/react-router';
const form = { name: '', age: 0 };
const { urlState, setState, setUrl } = useUrlState(form);
// Update state without changing URL
setState({ name: 'test' });
setState(currVal => ({ ...currVal, name: 'test' }) );
// reset state
setState((_curr, initial) => initial);
// Update state and URL
// options from type `NavigateOptions` from 'react-router`
setUrl({ name: 'test' }, { replace: false, preventScrollReset: false });
// reset state and URL
setUrl((_curr, initial) => initial);
```
--------------------------------
### Valid and Invalid JSONCompatible Examples
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md
Illustrates valid and invalid examples of the JSONCompatible type. Valid states include basic types, Dates, nested objects, and arrays. Invalid states contain functions, non-JSON types, or symbols.
```typescript
// ✅ Valid JSONCompatible
const validState = {
name: 'John',
age: 30,
joined: new Date('2024-01-15'),
tags: ['react', 'typescript'],
settings: {
theme: 'dark',
notifications: true,
},
inactive: undefined,
};
// ❌ Invalid (not JSONCompatible)
const invalidState = {
callback: () => {},
regex: /pattern/,
symbol: Symbol('id'),
};
```
--------------------------------
### Run Full Test Suite
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Execute the complete test suite, including type checking, unit tests, build, and integration tests. This is the command used in CI.
```bash
pnpm run test
```
--------------------------------
### Discrete Control with Direct setUrl
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/input-handling/SKILL.md
Demonstrates using setUrl directly for discrete controls like buttons, as they typically fire infrequently.
```typescript
```
--------------------------------
### Framework Wrapper Pattern
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/architecture.md
This pattern shows how a framework-specific hook adapts the router and options, then combines state, history synchronization, and debouncing using `useSharedState`, `useUrlEncode`, and a history listener.
```text
Framework-specific hook
↓ adapts router and options
useUrlStateBase
↓ combines state + history sync + debounce
├─ useSharedState (cross-component sync)
├─ useUrlEncode (encode/decode functions)
└─ history listener (popstate handling)
```
--------------------------------
### getSearch()
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/utilities.md
Gets the current window location search string. Returns the browser's `window.location.search` or an empty string on the server.
```APIDOC
## `getSearch()`
### Description
Gets current window location search string.
### Returns
- Browser: `window.location.search` (e.g., `'?name=John&age=30'`)
- Server: Empty string `''`
### Example
```typescript
import { getSearch } from 'state-in-url';
getSearch(); // Browser: '?name=John&age=30'
getSearch(); // Server: ''
```
```
--------------------------------
### Basic Usage of useUrlEncode
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlEncode.md
Demonstrates how to use the stringify and parse functions returned by useUrlEncode to convert state to a query string and back. Note that default values are omitted during stringification.
```typescript
import { useUrlEncode } from 'state-in-url';
const form = {
name: '',
age: 0,
tags: [],
joinedAt: new Date(),
};
function SearchComponent() {
const { stringify, parse } = useUrlEncode(form);
// Encode state to query string
const query = stringify({
name: 'Alice',
age: 28,
tags: [], // omitted if matches default
joinedAt: new Date('2024-01-15'),
});
console.log(query);
// Output: 'name=Alice&age=28&joinedAt=⏲2024-01-15T00:00:00.000Z'
// Decode query string back to state
const state = parse(query);
console.log(state);
// Output: {
// name: 'Alice',
// age: 28,
// tags: [],
// joinedAt: Date(2024-01-15)
// }
}
```
--------------------------------
### Import All Main Utilities
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/README.md
Imports all primary hooks and utilities from the `state-in-url` package, including `useUrlState`, `useSharedState`, and various encoding functions.
```typescript
import {
useUrlState,
useSharedState,
encode,
decode,
encodeState,
decodeState,
typeOf,
isSSR,
} from 'state-in-url';
```
--------------------------------
### URL Parameter Handling Utilities
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/MANIFEST.md
Functions for handling URL parameters, including getting parameters from a URL and filtering unknown parameters.
```typescript
import { getParams, filterUnknownParams, filterUnknownParamsClient } from "state-in-url/utils";
// Example usage:
const url = new URL("http://example.com?a=1&b=2&c=3");
const params = getParams(url);
console.log(params); // { a: "1", b: "2", c: "3" }
const allowedParams = { a: "1" };
const filtered = filterUnknownParams(params, allowedParams);
console.log(filtered); // { a: "1" }
// filterUnknownParamsClient is similar but may have client-specific logic.
```
--------------------------------
### SSR Initial State Hydration
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/shared-state-no-url/SKILL.md
Provide a function as the second argument to `useSharedState` to hydrate the initial state on the server, for example, by reading from a cookie.
```typescript
const { state } = useSharedState(CART_STATE, () => readFromCookie());
```
--------------------------------
### Run Integration Tests
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md
Executes the integration tests. Requires the demo project to be running (`npm run dev`).
```bash
npm run test:int
```
--------------------------------
### Imperative State Access
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useSharedState.md
Shows how to get the current state value imperatively without triggering a re-render. Useful for reading state before an asynchronous operation.
```typescript
const { getState } = useSharedState(userState);
const handleAsync = async () => {
const current = getState();
const result = await fetchData(current.id);
// Use current without race condition
};
```
--------------------------------
### Run All Tests
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md
Executes all unit and end-to-end tests for the project.
```bash
npm run test
```
--------------------------------
### setState Usage Example
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-next.md
Demonstrates how to update the component's state without immediately syncing it to the URL, useful for debouncing URL updates during form input.
```typescript
// merge with current state
setState({ name: 'John' })
// updater function with access to current and initial state
setState((curr, initial) => ({ ...curr, age: 30 }))
```
--------------------------------
### Test LLM Content with Curl
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs14/README-llms-txt.md
Use curl to test how the application responds to different Accept headers. The first command requests markdown, while the second requests HTML.
```bash
curl -H "Accept: text/markdown" http://localhost:3000
# Should return markdown content
curl -H "Accept: text/html" http://localhost:3000
# Should return HTML
```
--------------------------------
### Use useUrlState Hook in Next.js App Router
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Example of using the `useUrlState` hook for Next.js App Router. It handles SSR and defaults to window.history navigation.
```typescript
import { useUrlState } from "state-in-url/next";
// Example usage in a Next.js App Router component
function MyComponent() {
const [value, setValue] = useUrlState("myKey", "defaultValue");
return (
Current value: {value}
);
}
```
--------------------------------
### URLSearchParams Initialization
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md
Illustrates how to initialize URLSearchParams with either a query string or an array of key-value pairs.
```typescript
new URLSearchParams('name=John&age=30');
new URLSearchParams([['name', 'John'], ['age', '30']]);
```
--------------------------------
### state-in-url (default export)
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/entry-points.md
The main package provides a complete library with framework-agnostic utilities and a Next.js hook. It exports hooks like `useUrlState` and `useSharedState`, encoding functions such as `encode` and `decode`, and utility functions like `typeOf`.
```APIDOC
## state-in-url (default export)
### Description
Provides a comprehensive library with framework-agnostic utilities and a Next.js hook. Suitable for Next.js users, utility consumers, and most applications.
### Exports
- **Hooks:** `useUrlState`, `useSharedState`, `useUrlEncode`, `useUrlStateBase`
- **Encoding functions:** `encode`, `decode`, `encodeState`, `decodeState`
- **Utilities:** `typeOf`, `isSSR`
- **Types:** `JSONCompatible`, `Type`
```
--------------------------------
### React Router v6 Setup with useUrlState
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/react-router-remix-setup/SKILL.md
Use the useUrlState hook from 'state-in-url/react-router6' for React Router v6 projects. This import path is specific to v6 and later versions of state-in-url.
```typescript
// Note the /react-router6 subpath
import { useUrlState } from 'state-in-url/react-router6';
type FiltersState = { sort: 'name' | 'date'; page: number };
const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
export function FiltersBar() {
const { urlState, setUrl } = useUrlState(FILTERS_STATE);
return ;
}
```
--------------------------------
### Detect Value Type with typeOf
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/utilities.md
Use `typeOf` to get detailed type information beyond JavaScript's native `typeof`. Useful for custom serialization or type-based routing.
```typescript
import { typeOf } from 'state-in-url';
typeOf(null);
// 'null'
typeOf([1, 2, 3]);
// 'array'
typeOf({});
// 'object'
typeOf(new Date());
// 'date'
typeOf(42);
// 'number'
typeOf('hello');
// 'string'
typeOf(true);
// 'boolean'
typeOf(undefined);
// 'undefined'
typeOf(() => {});
// 'function'
typeOf(Symbol('id'));
// 'symbol'
typeOf(1n);
// 'bigint'
// Differences from typeof
typeof null;
// 'object'
typeOf(null);
// 'null'
typeof [1, 2];
// 'object'
typeOf([1, 2]);
// 'array'
typeof new Date();
// 'object'
typeOf(new Date());
// 'date'
```
--------------------------------
### Basic useUrlState Hook Usage
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs15/public/llms.txt
Demonstrates the basic usage of the `useUrlState` hook, including state retrieval, synchronous internal state updates, and URL updates.
```typescript
const { urlState, setState, setUrl, reset } = useUrlState(DEFAULT_STATE, options?);
```
--------------------------------
### Using useSharedState Hook
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useSharedState/README.md
Demonstrates how to initialize and use the useSharedState hook to manage shared form state. Shows how to update the state using direct object assignment or a functional update, and how to retrieve the current state.
```typescript
import { useSharedState } from 'state-in-url/useSharedState';
const form = { name: '', age: 0 };
const { state, getState, setState } = useSharedState(form);
// Update state
setState({ name: 'test' });
// Or update state using a function
setState(curr => ({ ...curr, name: 'test' }));
// Get current state
const currentState = getState();
```
--------------------------------
### Main Package Exports
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/entry-points.md
Imports all utilities, hooks, and types from the main 'state-in-url' package. Recommended for Next.js users, utility consumers, and most applications.
```typescript
import {
// Hooks
useUrlState, // Next.js hook
useSharedState, // Cross-component state
useUrlEncode, // Low-level encode/decode
useUrlStateBase, // Generic hook base
// Encoding functions
encode, // Value → URL string
decode, // URL string → value
encodeState, // State → query string
decodeState, // Query string → state
// Utilities
typeOf, // Enhanced typeof
isSSR, // Server environment detection
// Types
JSONCompatible,
Type,
} from 'state-in-url';
```
--------------------------------
### Run Unit Tests
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md
Execute Vitest unit tests. This command runs in watch mode by default and enables coverage.
```bash
pnpm run test:unit
```
--------------------------------
### Conditional URL State Updates
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-remix.md
Implement logic for conditional updates to the URL state based on user interactions. This example shows how to toggle sort order or set a new sort field.
```typescript
const { setUrl, urlState } = useUrlState(form);
const handleSort = (sortBy) => {
if (urlState.sort === sortBy) {
setUrl({ sortAsc: !urlState.sortAsc });
} else {
setUrl({ sort: sortBy, sortAsc: true });
}
};
```
--------------------------------
### useUrlState Options
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs15/public/llms.txt
Explains the `options` object that can be passed to `useUrlState` for controlling URL update behavior like `replace` and `scroll`, and for SSR correctness in Next.js.
```typescript
// options (per-call or as hook-level defaults):
// - replace?: boolean — router.replace (default true) vs router.push.
// - scroll?: boolean — Next.js scroll behavior (default false).
// React Router / Remix: any NavigateOptions (e.g. preventScrollReset).
// Hook-level options (second arg to useUrlState):
// - searchParams — pass searchParams from a Next.js server component or useSearchParams() from a client component. Required for SSR correctness in Next.js App Router.
// - useHistory?: boolean — Next.js only. Default true. Uses window.history.pushState to avoid _rsc server round-trips on URL changes. Flip to false only when server data must refetch on URL change.
```
--------------------------------
### Basic Usage of useUrlState Hook
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/next/useUrlState/README.md
Demonstrates how to initialize the hook with default form values and use setState to update state locally without affecting the URL. Also shows how to use setUrl to update both state and URL, including options for replace and scroll behavior.
```typescript
import { useUrlState } from 'state-in-url/next';
const form = { name: '', age: 0 };
const { urlState, setState, setUrl } = useUrlState(form);
// Update state without changing URL
setState({ name: 'test' });
// API same as React.useState
setState(currVal => ({ ...currVal, name: 'test' }) );
// reset state
setState((_curr, initial) => initial);
// Update state and URL
setUrl({ name: 'test' }, { replace: false, scroll: true });
// reset state and URL
setUrl((_curr, initial) => initial);
```
--------------------------------
### setUrl with Navigate Function
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md
Shows how the setUrl function, when useHistory is false (default), calls React Router's navigate function to update both the state and the URL. Includes example options for navigation.
```typescript
setUrl({ page: 2 }, { replace: true, preventScrollReset: true });
// Calls: navigate('?page=2', { replace: true, preventScrollReset: true })
```
--------------------------------
### useUrlStateBase Hook
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useUrlStateBase/README.md
A custom React hook to create custom `useUrlState` hooks. It requires a default state, a router object with push and replace methods, and optionally a function to get the initial state.
```APIDOC
## `useUrlStateBase` hook
A custom React hook to create custom `useUrlState` hooks.
### Parameters:
- `defaultState` (object) - An object representing the default state values.
- `router` (object) - Router object with `push` and `replace` methods
- `getInitialState?` (function) - Optional function that return initial state.
### Returns:
An object containing:
- `state` (object) - The current state.
- `getState` (Function) - Function to get state.
- `updateState` (Function) - Function to update the state without updating the URL.
- `updateUrl` (Function) - Function to update both the state and the URL.
- `reset` (Function) - Function to reset state and url to default values
```
--------------------------------
### setUrl Behavior: Window History vs Next.js Router
Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-next.md
Illustrates the difference in URL updating behavior between using the default `window.history` and explicitly disabling it to use the Next.js router.
```typescript
// useHistory: true (default)
setUrl({ page: 2 });
// → window.history.replaceState(null, '', '?page=2')
// → No server revalidation, no _rsc param
// useHistory: false
setUrl({ page: 2 });
// → router.push('?page=2')
// → May trigger RSC revalidation
```