Skip to content

URL State

URL state syncs mesh state to browser URL query parameters. Changes to state update the URL; browser back/forward and direct URL changes update state.

Define URL State

ts
mesh.urlState("products.filters", {
  search: "",
  category: "all",
  page: 1,
  sort: "latest"
}, {
  paramNames: {
    search: "q",
    category: "cat",
    page: "p"
  }
});

Use in React

tsx
import { useMeshUrlState } from "statemesh-core";

function ProductFilters() {
  const [filters, setFilters] = useMeshUrlState<{
    search: string;
    category: string;
    page: number;
    sort: string;
  }>("products.filters");

  return (
    <div>
      <input
        value={filters.search}
        onChange={(e) => setFilters({ search: e.target.value, page: 1 })}
      />
      <select
        value={filters.category}
        onChange={(e) => setFilters({ category: e.target.value })}
      >
        <option value="all">All</option>
        <option value="electronics">Electronics</option>
      </select>
    </div>
  );
}

This reads and writes URLs like:

/products?q=keyboard&cat=electronics&p=1&sort=latest

Custom Param Names

Use paramNames to map state fields to URL-friendly parameter names:

ts
mesh.urlState("filters", {
  search: "",
  page: 1,
  sale: false
}, {
  paramNames: {
    search: "q",
    page: "p",
    sale: "available"
  }
});

URL: /products?q=keyboard&p=2&available=true

Resolver Function

For fully custom naming, use a resolver function:

ts
mesh.urlState("filters", defaults, {
  paramNames: (field) => `filter_${field}`
});

paramNames takes priority over paramPrefix; unmapped fields fall back to paramPrefix or the field name.

Capture Unknown Params

Dynamic query params can be captured into one object field:

ts
mesh.urlState("products.filters", {
  search: "",
  params: {} as Record<string, string>
}, {
  paramNames: {
    search: "q"
  },
  captureUnknown: /^filter_/,
  unknownField: "params"
});

URL: /products?q=keyboard&filter_brand=keychron Result: { search: "keyboard", params: { filter_brand: "keychron" } }

Options

OptionTypeDescription
paramNamesRecord<string, string> | (field) => stringMap state fields to URL param names
paramPrefixstringPrefix for all params (fallback)
captureUnknownRegExpCapture unknown params matching this pattern
unknownFieldstringField to store captured unknown params
replacebooleanUse replaceState instead of pushState
debouncenumberDebounce URL updates in ms

History Adapters

ts
import { createBrowserHistory, createMemoryHistory } from "statemesh-core/router";

// Browser history (default)
const browserHistory = createBrowserHistory("/app");

// Memory history (for testing and SSR)
const memoryHistory = createMemoryHistory("/", ["/products", "/products/kbd"]);

SSR Safety

URL state is SSR-guarded. In server environments (where window is undefined), the URL state is registered but no browser APIs are accessed.

Important Notes

TIP

URL state is SSR-safe. All browser API access is guarded with isBrowser() checks.

WARNING

Setting replace: true prevents the browser back button from capturing every filter change. Use it for high-frequency updates like search input.

TIP

Use paramNames when the URL should use API/product-friendly names instead of state field names.

Next Steps

Released under the MIT License.