Gesamtwert der KI-Bereitschaft
Zusammengefasster Wert aus allen Auditsignalen.
Gesamtwert der KI-Bereitschaft
Zusammengefasster Wert aus allen Auditsignalen.
Gesamtbewertung der KI-Bereitschaft
state-in-url (state-in-url.dev) erreichte im automatisierten technischen Audit 71/100 Punkte bei der KI-Bereitschaft. llms.txt war erreichbar, llms-full.txt hatte keine erreichbare Datei und ai.txt war verfügbar. Die robots.txt-Analyse ergab 0 ausdrücklich erlaubte und 0 blockierte KI-Crawler sowie 1 deklarierte Sitemap. Die Vollständigkeit des Homepage-Markups lag bei 0%; es wurden keine Schema.org-Typen erkannt. Erkannte OpenGraph-Tags: 0. Die Ergebnisse entsprechen den öffentlich erreichbaren Antworten der Website zum Prüfzeitpunkt 2026-07-21T05:47:11.824Z.
Die Prüfung kombiniert maschinenlesbare Dateien, Crawler-Regeln, Sitemaps und Homepage-Markup. llms.txt ist erreichbar und umfasst 2.702 Tokens.
robots.txt ist verfügbar; blockierte KI-Bots: 0. Deklarierte Sitemaps: 1. Keine Schema.org-Typen erkannt.
Mobiles Lighthouse-Profil: Performance 83/100, Barrierefreiheit 100/100, SEO 100/100.
Eine mobile Lighthouse-Messung. Die experimentelle Kategorie Agentic Browsing wird separat gezeigt und ersetzt nicht den LLMSMap-Gesamtwert.
Performance
Barrierefreiheit
Best Practices
Technisches SEO
Agentic Browsing
Die mobile Performance liegt bei 83/100; der größte sichtbare Inhalt erschien nach 4.1 s und der Hauptthread war für 220 ms blockiert. Die Layout-Verschiebung betrug 0. Lange Aufgaben verzögern Eingaben von Nutzern und Browser-Agenten.
Barrierefreiheit: 100/100, Best Practices: 100/100, technisches SEO: 100/100. Die experimentelle Kategorie Agentic Browsing erreichte 100/100 und wird getrennt vom LLMSMap-Gesamtwert angezeigt.
Lange JavaScript-Aufgaben aufteilen, nicht kritische Skripte und Stile verzögern und blockierende Anfrageketten verkürzen.
Ungenutztes CSS und JavaScript entfernen, schwere Widgets bei Bedarf laden und Drittanbieter-Skripte begrenzen.
Erster Inhalt
Hauptinhalt
Layout-Stabilität
Blockierzeit
Visuelle Geschwindigkeit
Maschinenlesbare Dateien, Crawler-Regeln, Discovery und Homepage-Markup.
Vollständige Version wurde nicht gefunden
1 Sitemap gefunden
Keine Schema.org-Auszeichnung auf der Startseite gefunden
Keine OpenGraph-Tags auf der Startseite gefunden
Basierend auf der robots.txt-Analyse
Deklarierte Discovery-Routen für Crawler und Agenten.
# state-in-url
> A React hook library for storing typed, JSON-serializable state in URL query parameters. ~2 KB, zero runtime deps. Supports the Next.js App Router (14/15/16), React Router 6/7, Remix 2, Astro (React/Preact islands), and plain React. MIT licensed.
Last updated: 2026-08-31. Canonical: <https://state-in-url.dev/llms.txt>.
## For AI coding agents — preferred path
This package ships task-focused SKILL.md files via [@tanstack/intent](https://tanstack.com/intent/latest/docs/overview). If your agent supports Intent, that is the right surface to load instead of this file:
```bash
# in the user's project, once
npx @tanstack/intent@latest install
# list skills available for installed libraries
npx @tanstack/intent@latest list
# load a specific skill into the current context
npx @tanstack/intent@latest load state-in-url#feature-state-hook
```
Available skills (under `node_modules/state-in-url/skills/`):
| Skill | Type | When to load |
|---|---|---|
| `feature-state-hook` | core | Defining state and wrapping `useUrlState` in a feature-scoped custom hook |
| `input-handling` | core | Text inputs / sliders / fast-changing controls |
| `nextjs-ssr` | framework | Next.js App Router: `searchParams` forwarding, Proxy for layouts |
| `react-router-remix-setup` | framework | React Router v6/v7 or Remix v2 setup |
| `astro-setup` | framework | Astro: React/Preact islands with the `searchParams` prop, or no client framework via `encodeState`/`decodeState` |
| `form-library-integration` | composition | Pairing with `react-hook-form` (or formik) |
| `shared-state-no-url` | core | `useSharedState` — cross-component state without URL sync |
The rest of this file is a condensed reference for agents that cannot load Intent skills.
## Comparison with alternatives
Full page: <https://state-in-url.dev/vs/nuqs> (Markdown: /vs/nuqs.md). Sizes: whole-library import, esbuild minify + gzip, measured August 2026 (nuqs 2.10.1).
| Library | Setup | Nested objects and dates | Size | Pick it when |
|---|---|---|---|---|
| state-in-url | None - import the hook | Preserved automatically, types included | ~2.9 KB gzip, zero deps | One typed object, zero setup, on Next.js / React Router / Remix / Astro |
| nuqs | Adapter component, parser per key | JSON parser plus your own validator | ~6.7 KB gzip, one dep | Each value as its own readable query param |
| TanStack Router | validateSearch on each route | JSON-first; dates need custom serialization | Built into the router | You are on TanStack Router |
| use-query-params | Provider plus router adapter, param config per key | Via a JSON param type, loosely typed | ~4.4 KB gzip + serialize-query-params | A codebase already built on it |
| useSearchParams | None - built into the router | Strings only, everything by hand | 0 KB | One or two flat string params |
## Package info
- npm: https://www.npmjs.com/package/state-in-url
- repo: https://github.com/asmyshlyaev177/state-in-url
- website: https://state-in-url.dev
- full README: https://raw.githubusercontent.com/asmyshlyaev177/state-in-url/refs/heads/master/README.md
## Supported frameworks
| Framework | Versions | Import path |
|---|---|---|
| Next.js (App Router only) | 14 / 15 / 16 | `state-in-url/next` |
| React Router | v7 | `state-in-url/react-router` |
| React Router | v6 | `state-in-url/react-router6` |
| Remix | v2 | `state-in-url/remix` |
| Astro | React or Preact (compat) islands, on-demand rendered pages | `state-in-url/astro` |
| Framework-agnostic | — | `state-in-url` (`useSharedState`), `state-in-url/encodeState` |
Pages Router is **not** supported.
## Install
```bash
npm install state-in-url
```
In `tsconfig.json`, ensure `"moduleResolution": "Bundler"` (or `"Node16"` / `"NodeNext"`).
## Core rules — read first
1. **Type, never interface.** The hook's generic constraint `JSONCompatible<T>` rejects `interface`. Always declare a `type` AND annotate the const: `const FOO_STATE: FooState = { ... }`.
2. **Default-state object must be a module-scoped `const`.** Never built from props, hook returns, or destructuring inside a component. Sharing is keyed by object identity.
3. **One feature → one shared default-state const → one custom hook.** Components import the hook, never `useUrlState` directly with their own defaults object.
4. **No secrets in URL.** Entity IDs (`jobId`, `memberId`) are fine; tokens, API keys, PII are not.
5. **JSON-serializable only.** Functions, BigInt, Symbol, Map, Set, class instances will not round-trip. Dates are supported.
6. **URL size**: keep total query-string under ~12 KB to stay safe across CDNs (Vercel header limit is 14 KB).
## API: `useUrlState`
```typescript
const { urlState, setState, setUrl, reset } = useUrlState(DEFAULT_STATE, options?);
```
- `urlState` — current state, typed identically to `DEFAULT_STATE`.
- `setState(value)` — updates internal state synchronously; **does not touch URL**.
- `setUrl(value, opts?)` — updates state + URL. URL write is throttled (next tick).
- `reset(opts?)` — sets state and URL back to `DEFAULT_STATE`.
Setter call signatures (both `setState` and `setUrl`):
```typescript
setUrl({ field: 'newValue' }); // partial patch
setUrl(curr => ({ ...curr, field: 'newValue' })); // functional with current
setUrl((curr, initial) => initial); // reset via callback
setUrl(); // flush current state to URL
```
`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. **Required for SSR correctness in Next.js App Router.** `useSearchParams()` is a fallback for components the prop cannot reach, and costs prerendering; see below.
- `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.
## Recommended pattern: feature-scoped hook
```typescript
// features/jobs/jobsState.ts
export type JobsState = {
status: '' | 'active' | 'closed';
tab: 'details' | 'qa' | 'applicants';
jobId: string;
};
export const JOBS_STATE: JobsState = {
status: '',
tab: 'details',
jobId: '',
};
```
```typescript
// features/jobs/useJobsState.ts
'use client';
import { useUrlState } from 'state-in-url/next';
import { JOBS_STATE } from './jobsState';
// `searchParams` comes from the server component at the top of the feature.
// Nested callers pass nothing and share the same store.
export function useJobsState(searchParams?: object) {
return useUrlState(JOBS_STATE, { searchParams });
}
```
Any component calling `useJobsState()` shares the same URL-synced store. No Context, no Provider.
Do not call `useSearchParams()` to feed the hook. It needs a `<Suspense>` boundary, opts the page out of prerendering, and buys nothing the server prop does not — on the client the hook already reads `window.location.search`. Thread `searchParams` from the server component. Reach for `useSearchParams()` only when a component genuinely cannot receive it, and accept the bailout.
## Next.js App Router — server page forwarding `searchParams`
In **Next.js 15+**, `searchParams` is a `Promise`:
```typescript
// app/jobs/page.tsx (Server Component)
import { JobsList } from './JobsList';
export default async function Page({
searchParams,
}: {
searchParams: Promise<Record<string, string | string[] | undefined>>;
}) {
const sp = await searchParams;
return <JobsList searchParams={sp} />;
}
// app/jobs/JobsList.tsx
'use client';
import { useUrlState } from 'state-in-url/next';
import { JOBS_STATE } from 'features/jobs/jobsState';
export function JobsList({ searchParams }: { searchParams: object }) {
const { urlState, setUrl } = useUrlState(JOBS_STATE, { searchParams });
// ...
}
```
Without `searchParams`, the first render uses defaults, then a client effect re-syncs from the URL on the next tick — visible flash plus hydration warning.
The hook does not call `useSearchParams` itself, so a component using it needs no `<Suspense>` boundary and does not opt its page out of prerendering — PPR and `cacheComponents: true` included. Initial state comes from `searchParams` on the server and `window.location.search` on the client; later changes are tracked through the History API, which also catches a bare `history.pushState` from unrelated code. A prerendered page still renders defaults, since there is no query string at build time — render dynamically when a shared stateful link must be correct on first paint.
## Next.js App Router — server layout (Proxy workaround)
Server layouts don't receive `searchParams`. Expose the query string via a Proxy header (Next.js 16+; `middleware.ts` still works as a deprecated alias):
```typescript
// proxy.ts
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
export function proxy(request: NextRequest) {
const sp = (request.url.includes('_next') ? '' : request.url).split('?')[1] ?? '';
const headers = new Headers(request.headers);
headers.set('searchParams', sp);
return NextResponse.next({ request: { headers } });
}
```
```typescript
// app/jobs/layout.tsx
import { headers } from 'next/headers';
import { decodeState } from 'state-in-url/encodeState';
import { JOBS_STATE } from 'features/jobs/jobsState';
export default async function Layout({ children }: { children: React.ReactNode }) {
const sp = (await headers()).get('searchParams') ?? '';
const initial = decodeState(sp, JOBS_STATE);
return <>{/* use `initial` */}{children}</>;
}
```
## Input handling — instant feedback, deferred URL write
For text inputs and other fast-changing controls, split `setState` (instant render) and `setUrl` (URL flush):
```typescript
<input
value={urlState.q}
onChange={(e) => setState({ q: e.target.value })}
onBlur={() => setUrl()}
/>
```
`setUrl()` with no args flushes the current state to the URL with content-based diffing — safe to call repeatedly.
## React Router and Remix
API is identical to the Next.js variant; only the import path and `NavigateOptions` differ.
```typescript
import { useUrlState } from 'state-in-url/react-router'; // RR v7
import { useUrlState } from 'state-in-url/react-router6'; // RR v6 (since 6.0.0)
import { useUrlState } from 'state-in-url/remix'; // Remix v2
setUrl({ tab: 'b' }, { replace: false, preventScrollReset: true });
```
## Astro
Same API inside a React (or Preact `compat: true`) island. Pass `Object.fromEntries(Astro.url.searchParams)` as the island's `searchParams` prop so the server render matches the URL — a plain object, `URLSearchParams` serializes to `{}`. The page must render on demand (`output: 'server'` or `export const prerender = false`, with an adapter). Islands sharing one default-state object share state; there is no client router, so `replace` defaults to `true`.
```astro
---
import { Filters } from '../components/Filters';
const searchParams = Object.fromEntries(Astro.url.searchParams);
---
<Filters client:load searchParams={searchParams} />
```
```typescript
import { useUrlState } from 'state-in-url/astro';
export function Filters({ searchParams }: { searchParams?: Record<string, string> }) {
const { urlState, setUrl } = useUrlState(FILTERS_STATE, { searchParams });
...
}
```
No client framework at all: `decodeState(Astro.url.searchParams, FILTERS_STATE)` and `encodeState(next, FILTERS_STATE, Astro.url.searchParams)` from `state-in-url/encodeState` do the same job in the frontmatter, for links.
## react-hook-form integration
Share one defaults object, hydrate `useForm` from `urlState`, push form changes back via RHF `subscribe()` (not `watch()`):
```typescript
const { urlState, setUrl } = useUrlState(FILTERS_STATE, { searchParams });
const form = useForm<FiltersState>({ defaultValues: urlState });
React.useEffect(() => {
const sub = form.subscribe({
formState: { values: true },
callback: ({ values }) => setUrl(values),
});
return () => sub();
}, [form, setUrl]);
```
## `useSharedState` — cross-component state without URL
```typescript
import { useSharedState } from 'state-in-url';
const CART_STATE: CartState = { items: [], isOpen: false };
const { state, setState } = useSharedState(CART_STATE);
```
Same module-scoped default-state-identity rule. Use only when URL sync is explicitly NOT wanted.
## Common mistakes (CRITICAL — fix any agent generating these)
| Mistake | Fix |
|---|---|
| `defaultState` defined inside a React component | Move to a module-scoped `const`, annotated with a `type` |
| `interface FeatureState { ... }` for state shape | Use `type FeatureState = { ... }` |
| `setUrl` inside `useEffect` with `urlState` in deps | Causes infinite loop; gate on the actual change or derive on read |
| Two components each declaring `const DEFAULTS = {...}` | Export one const from a shared file; components import the hook |
| `setUrl`/`setState` called during render | Move into a handler or effect |
| `interface` instead of `type` | Same as above; `type` is required |
| Reading `searchParams` in a Next.js server layout | Use the Proxy + `headers()` + `decodeState` pattern |
| Using `state-in-url/next` in Pages Router | Not supported; use App Router or build a custom hook with `useUrlStateBase` |
| Importing `state-in-url/react-router` in a RR v6 project | Use `state-in-url/react-router6` (moved in 6.0.0) |
| `setUrl({...})` for fast typing inputs | Use `setState` on change, `setUrl()` on blur |
| Mutating `urlState` directly | Always go through `setState`/`setUrl` |
| Storing functions / `BigInt` / `Symbol` / `Map` / `Set` | Not serializable; use plain JSON-compatible values (Date is OK) |
| Storing tokens / API keys / passwords / PII in URL | Use auth storage; URL state is fully public |
## Documentation resources
- Next.js App Router guide (searchParams forwarding, layouts, history, FAQ): https://state-in-url.dev/nextjs — Markdown at https://state-in-url.dev/nextjs.md
- Comparison with nuqs, TanStack Router, use-query-params: https://state-in-url.dev/vs/nuqs — Markdown at https://state-in-url.dev/vs/nuqs.md
- Full README (humans): https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
- URL size limits: https://github.com/asmyshlyaev177/state-in-url/blob/master/Limits.md
- Working examples per framework: `packages/example-nextjs{14,15,16}`, `packages/example-react-router{6,7}`, `packages/example-remix2`, `packages/example-astro`
- JSDoc comments are available in IDE for all exported functions
## Contact
- Issues and bug reports: https://github.com/asmyshlyaev177/state-in-url/issues
- Discussions: https://github.com/asmyshlyaev177/state-in-url/discussions
- Maintainer: Aleksandr Smyshliaev (asmyshlyaev177) — https://asmyshlyaev177.dev
## AI Discovery Files
- ai.txt (what AI systems may and may not do with this content): https://state-in-url.dev/ai.txt
- ai.json (the same policy, machine-parseable): https://state-in-url.dev/ai.json
- identity.json (canonical project identity): https://state-in-url.dev/identity.json
- brand.txt (correct naming and terminology): https://state-in-url.dev/brand.txt
- faq-ai.txt (direct answers to common questions): https://state-in-url.dev/faq-ai.txt
- developer-ai.txt (exports, API surface, constraints): https://state-in-url.dev/developer-ai.txt
- robots-ai.txt (AI crawler directives): https://state-in-url.dev/robots-ai.txt
Websites mit ähnlicher KI-Bereitschaft — vergleichen Sie llms.txt und Markup.