Initial Idea
Define an optional searchParams schema inside each route() entry.
Keys merge into the existing params object, giving type-safety to both href() and component props.
Example
export default [
index("./home.tsx"),
route("/city", "./city.tsx", {
searchParam1: z.string(),
page: z.number().min(1),
}),
] satisfies RouteConfig;
When user is already using flat routes you can augment the existing fs routes with ones with the search params, react router will deduplicate entries with the same path:
export default flatRoutes().then((fsRoutes) => {
return [
...fsRoutes,
route("/city", "./city.tsx", { searchParam1: z.string() }),
] satisfies RouteConfig
})
Usage
href("/city", { searchParam1: "x" });
function Page({ params }: Route.ComponentProps) {
const { searchParam1, } = params
}
Motivation
- Removes brittle, stringly-typed query handling (e.g., OAuth callbacks)
- Type-safe href() creation and component access
- Supports arrays (repeat keys), numbers, emails, etc.
Validation
Powered by standard-schema, so any validator (Zod, Yup, Ajv, …) can be plugged in.
Error Handling
Validation failures bubble to the route’s existing error boundary.
Scope & Compatibility
- Fully opt-in: no searchParams → current behavior
- Name-collision check keeps path params intact
- Not applicable to data-router or declarative <Routes> mode
FAQ
Why reuse params instead of adding searchParams? | Smaller surface; keeps href() and component props unchanged. |
Can I swap validation libraries? | Yes—standard-schema is just an adapter layer. |
What data types are supported? | Anything jsonschema can express—numbers, arrays, enums, email, etc. |
What happens on validation error? | Your route’s error boundary renders. |
Does this touch declarative routes? | No—those modes stay exactly as they are. |
Blockers
To extract the typescript code from the params schema defined using standard-schema we need to wait for jsonschema support in standard-schema first, or only support Zod initially.