Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
andrelandgraf avatar

Url State Patterns

  • 51 installs
  • 18 repo stars
  • Updated June 8, 2026
  • andrelandgraf/fullstackrecipes

Url-state-patterns is a Claude skill that syncs React state to URL query params with nuqs for shareable filters, search, and deep-linkable dialogs.

About

Url-state-patterns shows how to sync React state to URL query params using the nuqs library. It covers the required Suspense wrapper, parsers with defaults, clearing params, and driving deep-linkable dialogs from the URL. A developer uses it when building shareable filters, search, or URL-driven dialogs.

  • Wraps nuqs in a Suspense boundary since it reads useSearchParams
  • Uses parsers (parseAsString/Boolean/ArrayOf) with .withDefault() to keep URLs clean
  • Drives deep-linkable dialogs from a URL param for shareable back/forward state

Url State Patterns by the numbers

  • 51 all-time installs (skills.sh)
  • Ranked #1,297 of 2,245 Frontend Development skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

url-state-patterns capabilities & compatibility

Capabilities
frontend
Use cases
frontend
From the docs

What url-state-patterns says it does

nuqs reads `useSearchParams`, so it needs a Suspense boundary.
SKILL.md
Set a value to `null` to remove it from the URL.
SKILL.md
npx skills add https://github.com/andrelandgraf/fullstackrecipes --skill url-state-patterns

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs51
repo stars18
Last updatedJune 8, 2026
Repositoryandrelandgraf/fullstackrecipes

What it does

Shows how to sync React state to URL query params with nuqs for shareable filters, search, and deep-linkable dialogs.

Who is it for?

React/Next.js developers building shareable, URL-driven UI state with nuqs.

When should I use this skill?

Building shareable filters, search, or URL-driven dialogs.

What you get

  • URL-synced React components using useQueryState
  • Deep-linkable dialogs driven by URL params

Files

SKILL.mdMarkdownGitHub ↗

URL State Patterns

Sync React state to URL query params with nuqs.

Prerequisites

Complete these setup recipes first:

  • URL State with nuqs

Suspense Wrapper

nuqs reads useSearchParams, so it needs a Suspense boundary. Colocate it by exporting a public wrapper that suspends an internal client component — consumers then use the component without adding Suspense themselves.

import { Suspense } from "react";

type SearchInputProps = { placeholder?: string };

export function SearchInput(props: SearchInputProps) {
  return (
    <Suspense fallback={<input placeholder={props.placeholder} disabled />}>
      <SearchInputClient {...props} />
    </Suspense>
  );
}
"use client";

import { useQueryState, parseAsString } from "nuqs";

function SearchInputClient({ placeholder = "Search..." }: SearchInputProps) {
  const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));

  return (
    <input
      value={search}
      onChange={(e) => setSearch(e.target.value || null)}
      placeholder={placeholder}
    />
  );
}

Parsers

Replace useState with useQueryState plus a parser. Use .withDefault() to read a fallback while keeping the URL clean.

"use client";

import {
  useQueryState,
  parseAsString,
  parseAsBoolean,
  parseAsArrayOf,
} from "nuqs";

const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));
const [showArchived, setShowArchived] = useQueryState(
  "archived",
  parseAsBoolean.withDefault(false),
);
const [tags, setTags] = useQueryState(
  "tags",
  parseAsArrayOf(parseAsString).withDefault([]),
);

Clearing

Set a value to null to remove it from the URL. With .withDefault(), the param clears but reads return the default.

setSearch(null);

function clearFilters() {
  setSearch(null);
  setTags(null);
  setShowArchived(null);
}

Deep-Linkable Dialogs

Drive dialog visibility from a URL param so it's shareable and survives back/forward. Wrap in the same Suspense pattern.

import { Suspense } from "react";

type DeleteDialogProps = { onDelete: (id: string) => Promise<void> };

export function DeleteDialog(props: DeleteDialogProps) {
  return (
    <Suspense fallback={null}>
      <DeleteDialogClient {...props} />
    </Suspense>
  );
}
"use client";

import { useQueryState, parseAsString } from "nuqs";
import { AlertDialog, AlertDialogContent } from "@/components/ui/alert-dialog";

function DeleteDialogClient({ onDelete }: DeleteDialogProps) {
  const [deleteId, setDeleteId] = useQueryState("delete", parseAsString);

  async function handleDelete() {
    if (!deleteId) return;
    await onDelete(deleteId);
    setDeleteId(null);
  }

  return (
    <AlertDialog open={!!deleteId} onOpenChange={(open) => !open && setDeleteId(null)}>
      <AlertDialogContent>
        <Button onClick={handleDelete}>Delete</Button>
      </AlertDialogContent>
    </AlertDialog>
  );
}

Open it from anywhere by setting the param — setDeleteId("item-123") yields the deep link /items?delete=item-123.

function ItemRow({ item }: { item: Item }) {
  const [, setDeleteId] = useQueryState("delete", parseAsString);
  return (
    <Button variant="ghost" onClick={() => setDeleteId(item.id)}>
      Delete
    </Button>
  );
}

---

References

Related skills

FAQ

Why does nuqs need a Suspense boundary?

nuqs reads useSearchParams, which requires a Suspense boundary; the pattern colocates it in a public wrapper.

How do you clear a query param?

Set its value to null; with .withDefault() the param clears while reads return the default.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.