@tanstack/router-core 1.168.0 → 1.168.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
- "version": "1.168.0",
3
+ "version": "1.168.1",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -155,7 +155,7 @@
155
155
  "@tanstack/history": "1.161.6"
156
156
  },
157
157
  "devDependencies": {
158
- "@tanstack/store": "^0.9.1",
158
+ "@tanstack/store": "^0.9.2",
159
159
  "@tanstack/intent": "^0.0.14",
160
160
  "esbuild": "^0.27.4",
161
161
  "vite": "*"
@@ -23,7 +23,7 @@ sources:
23
23
 
24
24
  TanStack Router treats search params as JSON-first application state. They are automatically parsed from the URL into structured objects (numbers, booleans, arrays, nested objects) and validated via `validateSearch` on each route.
25
25
 
26
- > **CRITICAL**: When using `zodValidator()`, use `fallback()` from `@tanstack/zod-adapter`, NOT zod's `.catch()`. Using `.catch()` with the zod adapter makes the output type `unknown`, destroying type safety. This does not apply to Valibot or ArkType (which use their own fallback mechanisms).
26
+ > **CRITICAL**: When using `zodValidator()` and Zod v3, use `fallback()` from `@tanstack/zod-adapter`, NOT zod's `.catch()`. Using `.catch()` with the zod adapter makes the output type `unknown`, destroying type safety. This does not apply to Valibot or ArkType (which use their own fallback mechanisms). It also does not apply to Zod v4, which should use `.catch()` and not use the `zodValidator()`.
27
27
  > **CRITICAL**: Types are fully inferred. Never annotate the return of `useSearch()`.
28
28
 
29
29
  ## Setup: Zod Adapter (Recommended)
@@ -35,19 +35,16 @@ npm install zod @tanstack/zod-adapter
35
35
  ```tsx
36
36
  // src/routes/products.tsx
37
37
  import { createFileRoute } from '@tanstack/react-router'
38
- import { zodValidator, fallback } from '@tanstack/zod-adapter'
39
38
  import { z } from 'zod'
40
39
 
41
40
  const productSearchSchema = z.object({
42
- page: fallback(z.number(), 1).default(1),
43
- filter: fallback(z.string(), '').default(''),
44
- sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
45
- 'newest',
46
- ),
41
+ page: z.number().default(1).catch(1),
42
+ filter: z.string().default(''),
43
+ sort: z.enum(['newest', 'oldest', 'price']).default('newest').catch('newest'),
47
44
  })
48
45
 
49
46
  export const Route = createFileRoute('/products')({
50
- validateSearch: zodValidator(productSearchSchema),
47
+ validateSearch: productSearchSchema,
51
48
  component: ProductsPage,
52
49
  })
53
50
 
@@ -168,15 +165,14 @@ Parent route search params are automatically merged into child routes:
168
165
  ```tsx
169
166
  // src/routes/shop.tsx — parent defines shared params
170
167
  import { createFileRoute } from '@tanstack/react-router'
171
- import { zodValidator, fallback } from '@tanstack/zod-adapter'
172
168
  import { z } from 'zod'
173
169
 
174
170
  const shopSearchSchema = z.object({
175
- currency: fallback(z.enum(['USD', 'EUR']), 'USD').default('USD'),
171
+ currency: z.enum(['USD', 'EUR']).default('USD').catch('USD'),
176
172
  })
177
173
 
178
174
  export const Route = createFileRoute('/shop')({
179
- validateSearch: zodValidator(shopSearchSchema),
175
+ validateSearch: shopSearchSchema,
180
176
  })
181
177
  ```
182
178
 
@@ -201,7 +197,6 @@ function ShopProducts() {
201
197
 
202
198
  ```tsx
203
199
  import { createRootRoute, retainSearchParams } from '@tanstack/react-router'
204
- import { zodValidator } from '@tanstack/zod-adapter'
205
200
  import { z } from 'zod'
206
201
 
207
202
  const rootSearchSchema = z.object({
@@ -209,7 +204,7 @@ const rootSearchSchema = z.object({
209
204
  })
210
205
 
211
206
  export const Route = createRootRoute({
212
- validateSearch: zodValidator(rootSearchSchema),
207
+ validateSearch: rootSearchSchema,
213
208
  search: {
214
209
  middlewares: [retainSearchParams(['debug'])],
215
210
  },
@@ -220,7 +215,6 @@ export const Route = createRootRoute({
220
215
 
221
216
  ```tsx
222
217
  import { createFileRoute, stripSearchParams } from '@tanstack/react-router'
223
- import { zodValidator } from '@tanstack/zod-adapter'
224
218
  import { z } from 'zod'
225
219
 
226
220
  const defaults = { sort: 'newest', page: 1 }
@@ -231,7 +225,7 @@ const searchSchema = z.object({
231
225
  })
232
226
 
233
227
  export const Route = createFileRoute('/items')({
234
- validateSearch: zodValidator(searchSchema),
228
+ validateSearch: searchSchema,
235
229
  search: {
236
230
  middlewares: [stripSearchParams(defaults)],
237
231
  },
@@ -242,13 +236,11 @@ export const Route = createFileRoute('/items')({
242
236
 
243
237
  ```tsx
244
238
  export const Route = createFileRoute('/search')({
245
- validateSearch: zodValidator(
246
- z.object({
247
- retainMe: z.string().optional(),
248
- arrayWithDefaults: z.string().array().default(['foo', 'bar']),
249
- required: z.string(),
250
- }),
251
- ),
239
+ validateSearch: z.object({
240
+ retainMe: z.string().optional(),
241
+ arrayWithDefaults: z.string().array().default(['foo', 'bar']),
242
+ required: z.string(),
243
+ }),
252
244
  search: {
253
245
  middlewares: [
254
246
  retainSearchParams(['retainMe']),
@@ -281,7 +273,7 @@ const router = createRouter({
281
273
 
282
274
  ```tsx
283
275
  export const Route = createFileRoute('/products')({
284
- validateSearch: zodValidator(productSearchSchema),
276
+ validateSearch: productSearchSchema,
285
277
  // Pick ONLY the params the loader needs — not the entire search object
286
278
  loaderDeps: ({ search }) => ({ page: search.page }),
287
279
  loader: async ({ deps }) => {
@@ -292,7 +284,7 @@ export const Route = createFileRoute('/products')({
292
284
 
293
285
  ## Common Mistakes
294
286
 
295
- ### 1. HIGH: Using zod `.catch()` with `zodValidator()` instead of adapter `fallback()`
287
+ ### 1. HIGH: Using zod v3's `.catch()` with `zodValidator()` instead of adapter `fallback()`
296
288
 
297
289
  ```tsx
298
290
  // WRONG — .catch() with zodValidator makes the type unknown
@@ -304,6 +296,8 @@ import { fallback } from '@tanstack/zod-adapter'
304
296
  const schema = z.object({ page: fallback(z.number(), 1) })
305
297
  ```
306
298
 
299
+ **Important:** This only applies when using Zod v3, not when using Zod v4. For v4, using `.catch()` is correct.
300
+
307
301
  ### 2. HIGH: Returning entire search object from `loaderDeps`
308
302
 
309
303
  ```tsx
@@ -335,7 +329,7 @@ export const Route = createRootRoute({
335
329
 
336
330
  // CORRECT — parent must define validateSearch for children to inherit
337
331
  export const Route = createRootRoute({
338
- validateSearch: zodValidator(globalSearchSchema),
332
+ validateSearch: globalSearchSchema,
339
333
  component: RootComponent,
340
334
  })
341
335
  ```