From f15d7ce4fd33c3e1b977a9458380d6bafc3fbb10 Mon Sep 17 00:00:00 2001
From: Birk Skyum <birk.skyum@pm.me>
Date: Wed, 12 Nov 2025 20:58:22 +0100
Subject: [PATCH 1/6] docs(solid-router): search-validator-adapters

---
 .../search-validator-adapters/.gitignore      |   5 +
 .../.vscode/settings.json                     |  11 ++
 .../solid/search-validator-adapters/README.md |   6 +
 .../search-validator-adapters/index.html      |  12 ++
 .../search-validator-adapters/package.json    |  35 ++++
 .../postcss.config.mjs                        |   5 +
 .../src/components/Content.tsx                |   9 ++
 .../src/components/Header.tsx                 |  22 +++
 .../src/components/Search.tsx                 |  18 +++
 .../src/components/Users.tsx                  |  84 ++++++++++
 .../search-validator-adapters/src/main.tsx    |  39 +++++
 .../src/routeTree.gen.ts                      | 152 ++++++++++++++++++
 .../src/routes/__root.tsx                     |  20 +++
 .../src/routes/index.tsx                      |  15 ++
 .../src/routes/users/arktype.index.tsx        |  44 +++++
 .../src/routes/users/valibot.index.tsx        |  40 +++++
 .../src/routes/users/zod.index.tsx            |  45 ++++++
 .../search-validator-adapters/src/styles.css  |  21 +++
 .../tests/arktype.test-d.tsx                  |  16 ++
 .../tests/arktype.test.tsx                    |  64 ++++++++
 .../tests/valibot.test-d.tsx                  |  14 ++
 .../tests/valibot.test.tsx                    |  61 +++++++
 .../search-validator-adapters/tsconfig.json   |  13 ++
 .../search-validator-adapters/vite.config.ts  |  22 +++
 pnpm-lock.yaml                                |  61 +++++++
 25 files changed, 834 insertions(+)
 create mode 100644 examples/solid/search-validator-adapters/.gitignore
 create mode 100644 examples/solid/search-validator-adapters/.vscode/settings.json
 create mode 100644 examples/solid/search-validator-adapters/README.md
 create mode 100644 examples/solid/search-validator-adapters/index.html
 create mode 100644 examples/solid/search-validator-adapters/package.json
 create mode 100644 examples/solid/search-validator-adapters/postcss.config.mjs
 create mode 100644 examples/solid/search-validator-adapters/src/components/Content.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/components/Header.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/components/Search.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/components/Users.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/main.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/routeTree.gen.ts
 create mode 100644 examples/solid/search-validator-adapters/src/routes/__root.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/routes/index.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/routes/users/valibot.index.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/routes/users/zod.index.tsx
 create mode 100644 examples/solid/search-validator-adapters/src/styles.css
 create mode 100644 examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
 create mode 100644 examples/solid/search-validator-adapters/tests/arktype.test.tsx
 create mode 100644 examples/solid/search-validator-adapters/tests/valibot.test-d.tsx
 create mode 100644 examples/solid/search-validator-adapters/tests/valibot.test.tsx
 create mode 100644 examples/solid/search-validator-adapters/tsconfig.json
 create mode 100644 examples/solid/search-validator-adapters/vite.config.ts

diff --git a/examples/solid/search-validator-adapters/.gitignore b/examples/solid/search-validator-adapters/.gitignore
new file mode 100644
index 0000000000..d451ff16c1
--- /dev/null
+++ b/examples/solid/search-validator-adapters/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+*.local
diff --git a/examples/solid/search-validator-adapters/.vscode/settings.json b/examples/solid/search-validator-adapters/.vscode/settings.json
new file mode 100644
index 0000000000..00b5278e58
--- /dev/null
+++ b/examples/solid/search-validator-adapters/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+  "files.watcherExclude": {
+    "**/routeTree.gen.ts": true
+  },
+  "search.exclude": {
+    "**/routeTree.gen.ts": true
+  },
+  "files.readonlyInclude": {
+    "**/routeTree.gen.ts": true
+  }
+}
diff --git a/examples/solid/search-validator-adapters/README.md b/examples/solid/search-validator-adapters/README.md
new file mode 100644
index 0000000000..115199d292
--- /dev/null
+++ b/examples/solid/search-validator-adapters/README.md
@@ -0,0 +1,6 @@
+# Example
+
+To run this example:
+
+- `npm install` or `yarn`
+- `npm start` or `yarn start`
diff --git a/examples/solid/search-validator-adapters/index.html b/examples/solid/search-validator-adapters/index.html
new file mode 100644
index 0000000000..9b6335c0ac
--- /dev/null
+++ b/examples/solid/search-validator-adapters/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Vite App</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.tsx"></script>
+  </body>
+</html>
diff --git a/examples/solid/search-validator-adapters/package.json b/examples/solid/search-validator-adapters/package.json
new file mode 100644
index 0000000000..c614275f66
--- /dev/null
+++ b/examples/solid/search-validator-adapters/package.json
@@ -0,0 +1,35 @@
+{
+  "name": "tanstack-solid-router-search-validator-adapters",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite --port 3000",
+    "build": "vite build && tsc --noEmit",
+    "serve": "vite preview",
+    "start": "vite",
+    "test:unit": "vitest"
+  },
+  "dependencies": {
+    "@tailwindcss/postcss": "^4.1.15",
+    "@tanstack/arktype-adapter": "^1.135.2",
+    "@tanstack/solid-query": "^5.90.0",
+    "@tanstack/solid-router": "^1.135.2",
+    "@tanstack/solid-router-devtools": "^1.135.2",
+    "@tanstack/router-plugin": "^1.135.2",
+    "@tanstack/valibot-adapter": "^1.135.2",
+    "@tanstack/zod-adapter": "^1.135.2",
+    "arktype": "^2.1.7",
+    "postcss": "^8.5.1",
+    "solid-js": "^1.9.10",
+    "tailwindcss": "^4.1.15",
+    "valibot": "1.0.0-beta.15",
+    "zod": "^3.24.2"
+  },
+  "devDependencies": {
+    "@testing-library/jest-dom": "^6.6.3",
+    "@solidjs/testing-library": "^0.8.10",
+    "vite-plugin-solid": "^2.11.10",
+    "typescript": "^5.7.2",
+    "vite": "^7.1.7"
+  }
+}
diff --git a/examples/solid/search-validator-adapters/postcss.config.mjs b/examples/solid/search-validator-adapters/postcss.config.mjs
new file mode 100644
index 0000000000..a7f73a2d1d
--- /dev/null
+++ b/examples/solid/search-validator-adapters/postcss.config.mjs
@@ -0,0 +1,5 @@
+export default {
+  plugins: {
+    '@tailwindcss/postcss': {},
+  },
+}
diff --git a/examples/solid/search-validator-adapters/src/components/Content.tsx b/examples/solid/search-validator-adapters/src/components/Content.tsx
new file mode 100644
index 0000000000..dbfa7ecff8
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/components/Content.tsx
@@ -0,0 +1,9 @@
+import type { JSX } from 'solid-js'
+
+export interface ContentProps {
+  readonly children: JSX.Element
+}
+
+export const Content = ({ children }: ContentProps) => {
+  return <section class="my-2 flex flex-col gap-2">{children}</section>
+}
diff --git a/examples/solid/search-validator-adapters/src/components/Header.tsx b/examples/solid/search-validator-adapters/src/components/Header.tsx
new file mode 100644
index 0000000000..5b119d38e5
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/components/Header.tsx
@@ -0,0 +1,22 @@
+import { Link } from '@tanstack/solid-router'
+
+const HeaderLink: typeof Link = (props) => {
+  return <Link class="text-lg text-blue-700" {...props} />
+}
+
+export interface HeaderProps {
+  readonly title: string
+}
+
+export const Header = ({ title }: HeaderProps) => {
+  return (
+    <header class="flex items-end gap-8 border-b-2 border-slate-150 py-4">
+      <h1 class="text-4xl">{title}</h1>
+      <nav class="flex gap-4">
+        <HeaderLink to="/users/zod">Zod</HeaderLink>
+        <HeaderLink to="/users/valibot">Valibot</HeaderLink>
+        <HeaderLink to="/users/arktype">Arktype</HeaderLink>
+      </nav>
+    </header>
+  )
+}
diff --git a/examples/solid/search-validator-adapters/src/components/Search.tsx b/examples/solid/search-validator-adapters/src/components/Search.tsx
new file mode 100644
index 0000000000..09c3d300da
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/components/Search.tsx
@@ -0,0 +1,18 @@
+export interface SearchProps {
+  search: string
+  onChange: (search: string) => void
+}
+
+export const Search = ({ search, onChange }: SearchProps) => {
+  return (
+    <div class="flex gap-2 align-center items-center">
+      <label>Search</label>
+      <input
+        type="search"
+        class="border p-1 px-2 rounded-sm"
+        value={search}
+        onInput={(e) => onChange(e.currentTarget.value)}
+      ></input>
+    </div>
+  )
+}
diff --git a/examples/solid/search-validator-adapters/src/components/Users.tsx b/examples/solid/search-validator-adapters/src/components/Users.tsx
new file mode 100644
index 0000000000..2c4b420dd8
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/components/Users.tsx
@@ -0,0 +1,84 @@
+import { queryOptions, useQuery } from '@tanstack/solid-query'
+
+export interface Geo {
+  lat: string
+  lng: string
+}
+
+export interface Address {
+  street: string
+  suite: string
+  city: string
+  zipcode: string
+  geo: Geo
+}
+
+export interface Company {
+  name: string
+  catchPhrase: string
+  bs: string
+}
+
+export interface User {
+  id: number
+  name: string
+  username: string
+  email: string
+  address: Address
+  phone: string
+  website: string
+  company: Company
+}
+
+export const getUsers = async (): Promise<Array<User>> => {
+  const response = await fetch('https://jsonplaceholder.typicode.com/users')
+  const users: Array<User> = await response.json()
+  return users
+}
+
+export const searchUsers = async (search: string): Promise<Array<User>> => {
+  const users = await getUsers()
+  const normalizedSearch = search.toLowerCase()
+  return users.filter(
+    (user) =>
+      user.name.toLowerCase().includes(normalizedSearch) ||
+      user.username.toLowerCase().includes(normalizedSearch),
+  )
+}
+
+export const usersQueryOptions = (search: string) =>
+  queryOptions({
+    queryKey: ['users', search],
+    queryFn: async () => {
+      return await searchUsers(search)
+    },
+  })
+
+export interface UsersProps {
+  search: string
+}
+
+export const Users = ({ search }: UsersProps) => {
+  const users = useQuery(() => usersQueryOptions(search))
+
+  return (
+    <table class="table-auto">
+      <thead>
+        <tr class="border text-left">
+          <th class="p-4">Username</th>
+          <th class="p-4">Name</th>
+          <th class="p-4">Email</th>
+        </tr>
+      </thead>
+      <tbody>
+        {users.data?.map((user) => (
+          <tr class="border">
+            <td class="p-4">{user.username}</td>
+            <td class="p-4">{user.name}</td>
+            <td class="p-4">{user.email}</td>
+          </tr>
+        ))}
+      </tbody>
+    </table>
+  )
+}
diff --git a/examples/solid/search-validator-adapters/src/main.tsx b/examples/solid/search-validator-adapters/src/main.tsx
new file mode 100644
index 0000000000..0d3d2e1b42
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/main.tsx
@@ -0,0 +1,39 @@
+import { render } from 'solid-js/web'
+import { RouterProvider, createRouter } from '@tanstack/solid-router'
+import { QueryClient, QueryClientProvider } from '@tanstack/solid-query'
+import { routeTree } from './routeTree.gen'
+import './styles.css'
+
+export const queryClient = new QueryClient()
+
+export const router = createRouter({
+  routeTree,
+  context: {
+    queryClient,
+  },
+  scrollRestoration: true,
+})
+
+declare module '@tanstack/solid-router' {
+  interface Register {
+    router: typeof router
+  }
+}
+
+export function App() {
+  return <RouterProvider router={router} />
+}
+
+const rootElement = document.getElementById('app')!
+
+if (!rootElement.innerHTML) {
+  render(
+    () => (
+      <QueryClientProvider client={queryClient}>
+        <App />
+      </QueryClientProvider>
+    ),
+
+    rootElement,
+  )
+}
diff --git a/examples/solid/search-validator-adapters/src/routeTree.gen.ts b/examples/solid/search-validator-adapters/src/routeTree.gen.ts
new file mode 100644
index 0000000000..3226feeab2
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/routeTree.gen.ts
@@ -0,0 +1,152 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/solid-router'
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+import { Route as UsersZodIndexRouteImport } from './routes/users/zod.index'
+import { Route as UsersValibotIndexRouteImport } from './routes/users/valibot.index'
+import { Route as UsersArktypeIndexRouteImport } from './routes/users/arktype.index'
+
+const IndexRoute = IndexRouteImport.update({
+  id: '/',
+  path: '/',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const UsersZodIndexRoute = UsersZodIndexRouteImport.update({
+  id: '/users/zod/',
+  path: '/users/zod/',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const UsersValibotIndexRoute = UsersValibotIndexRouteImport.update({
+  id: '/users/valibot/',
+  path: '/users/valibot/',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const UsersArktypeIndexRoute = UsersArktypeIndexRouteImport.update({
+  id: '/users/arktype/',
+  path: '/users/arktype/',
+  getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+  '/': typeof IndexRoute
+  '/users/arktype': typeof UsersArktypeIndexRoute
+  '/users/valibot': typeof UsersValibotIndexRoute
+  '/users/zod': typeof UsersZodIndexRoute
+}
+export interface FileRoutesByTo {
+  '/': typeof IndexRoute
+  '/users/arktype': typeof UsersArktypeIndexRoute
+  '/users/valibot': typeof UsersValibotIndexRoute
+  '/users/zod': typeof UsersZodIndexRoute
+}
+export interface FileRoutesById {
+  __root__: typeof rootRouteImport
+  '/': typeof IndexRoute
+  '/users/arktype/': typeof UsersArktypeIndexRoute
+  '/users/valibot/': typeof UsersValibotIndexRoute
+  '/users/zod/': typeof UsersZodIndexRoute
+}
+export interface FileRouteTypes {
+  fileRoutesByFullPath: FileRoutesByFullPath
+  fullPaths: '/' | '/users/arktype' | '/users/valibot' | '/users/zod'
+  fileRoutesByTo: FileRoutesByTo
+  to: '/' | '/users/arktype' | '/users/valibot' | '/users/zod'
+  id: '__root__' | '/' | '/users/arktype/' | '/users/valibot/' | '/users/zod/'
+  fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+  IndexRoute: typeof IndexRoute
+  UsersArktypeIndexRoute: typeof UsersArktypeIndexRoute
+  UsersValibotIndexRoute: typeof UsersValibotIndexRoute
+  UsersZodIndexRoute: typeof UsersZodIndexRoute
+}
+
+declare module '@tanstack/solid-router' {
+  interface FileRoutesByPath {
+    '/': {
+      id: '/'
+      path: '/'
+      fullPath: '/'
+      preLoaderRoute: typeof IndexRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/users/zod/': {
+      id: '/users/zod/'
+      path: '/users/zod'
+      fullPath: '/users/zod'
+      preLoaderRoute: typeof UsersZodIndexRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/users/valibot/': {
+      id: '/users/valibot/'
+      path: '/users/valibot'
+      fullPath: '/users/valibot'
+      preLoaderRoute: typeof UsersValibotIndexRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/users/arktype/': {
+      id: '/users/arktype/'
+      path: '/users/arktype'
+      fullPath: '/users/arktype'
+      preLoaderRoute: typeof UsersArktypeIndexRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+  }
+}
+
+declare module './routes/index' {
+  const createFileRoute: CreateFileRoute<
+    '/',
+    FileRoutesByPath['/']['parentRoute'],
+    FileRoutesByPath['/']['id'],
+    FileRoutesByPath['/']['path'],
+    FileRoutesByPath['/']['fullPath']
+  >
+}
+declare module './routes/users/arktype.index' {
+  const createFileRoute: CreateFileRoute<
+    '/users/arktype/',
+    FileRoutesByPath['/users/arktype/']['parentRoute'],
+    FileRoutesByPath['/users/arktype/']['id'],
+    FileRoutesByPath['/users/arktype/']['path'],
+    FileRoutesByPath['/users/arktype/']['fullPath']
+  >
+}
+declare module './routes/users/valibot.index' {
+  const createFileRoute: CreateFileRoute<
+    '/users/valibot/',
+    FileRoutesByPath['/users/valibot/']['parentRoute'],
+    FileRoutesByPath['/users/valibot/']['id'],
+    FileRoutesByPath['/users/valibot/']['path'],
+    FileRoutesByPath['/users/valibot/']['fullPath']
+  >
+}
+declare module './routes/users/zod.index' {
+  const createFileRoute: CreateFileRoute<
+    '/users/zod/',
+    FileRoutesByPath['/users/zod/']['parentRoute'],
+    FileRoutesByPath['/users/zod/']['id'],
+    FileRoutesByPath['/users/zod/']['path'],
+    FileRoutesByPath['/users/zod/']['fullPath']
+  >
+}
+
+const rootRouteChildren: RootRouteChildren = {
+  IndexRoute: IndexRoute,
+  UsersArktypeIndexRoute: UsersArktypeIndexRoute,
+  UsersValibotIndexRoute: UsersValibotIndexRoute,
+  UsersZodIndexRoute: UsersZodIndexRoute,
+}
+export const routeTree = rootRouteImport
+  ._addFileChildren(rootRouteChildren)
+  ._addFileTypes<FileRouteTypes>()
diff --git a/examples/solid/search-validator-adapters/src/routes/__root.tsx b/examples/solid/search-validator-adapters/src/routes/__root.tsx
new file mode 100644
index 0000000000..544efa185a
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/routes/__root.tsx
@@ -0,0 +1,20 @@
+import { Outlet, createRootRouteWithContext } from '@tanstack/solid-router'
+import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
+import type {QueryClient} from '@tanstack/solid-query';
+
+export interface Context {
+  queryClient: QueryClient
+}
+
+export const Route = createRootRouteWithContext<Context>()({
+  component: RootComponent,
+})
+
+function RootComponent() {
+  return (
+    <div class="m-4">
+      <Outlet />
+      <TanStackRouterDevtools />
+    </div>
+  )
+}
diff --git a/examples/solid/search-validator-adapters/src/routes/index.tsx b/examples/solid/search-validator-adapters/src/routes/index.tsx
new file mode 100644
index 0000000000..9a47bda715
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/routes/index.tsx
@@ -0,0 +1,15 @@
+import { Header } from '../components/Header'
+import { Content } from '../components/Content'
+
+export const Index = () => {
+  return (
+    <>
+      <Header title="Home" />
+      <Content>Welcome home</Content>
+    </>
+  )
+}
+
+export const Route = createFileRoute({
+  component: Index,
+})
diff --git a/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx b/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx
new file mode 100644
index 0000000000..6db9bb826d
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx
@@ -0,0 +1,44 @@
+import { useNavigate } from '@tanstack/solid-router'
+import { type } from 'arktype'
+import { Suspense } from 'solid-js'
+import { Header } from '../../components/Header'
+import { Users, usersQueryOptions } from '../../components/Users'
+import { Content } from '../../components/Content'
+import { Search } from '../../components/Search'
+
+const ArkType = () => {
+  const search = Route.useSearch({
+    select: (search) => search.search,
+  })
+  const navigate = useNavigate({ from: Route.fullPath })
+
+  return (
+    <>
+      <Header title="ArkType" />
+      <Content>
+        <Search
+          search={search()}
+          onChange={(search) => navigate({ search: { search }, replace: true })}
+        />
+        <Suspense>
+          <Users search={search()} />
+        </Suspense>
+      </Content>
+    </>
+  )
+}
+
+const search = type({
+  search: 'string = ""',
+})
+
+export const Route = createFileRoute({
+  validateSearch: search,
+  loaderDeps: (opt) => ({ search: opt.search }),
+  loader: (opt) => {
+    opt.context.queryClient.ensureQueryData(
+      usersQueryOptions(opt.deps.search.search),
+    )
+  },
+  component: ArkType,
+})
diff --git a/examples/solid/search-validator-adapters/src/routes/users/valibot.index.tsx b/examples/solid/search-validator-adapters/src/routes/users/valibot.index.tsx
new file mode 100644
index 0000000000..8358cdb89f
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/routes/users/valibot.index.tsx
@@ -0,0 +1,40 @@
+import { useNavigate } from '@tanstack/solid-router'
+import * as v from 'valibot'
+import { Suspense } from 'solid-js'
+import { Header } from '../../components/Header'
+import { Users, usersQueryOptions } from '../../components/Users'
+import { Content } from '../../components/Content'
+import { Search } from '../../components/Search'
+
+const Valibot = () => {
+  const search = Route.useSearch()
+  const navigate = useNavigate({ from: Route.fullPath })
+
+  return (
+    <>
+      <Header title="Valibot" />
+      <Content>
+        <Search
+          search={search().search}
+          onChange={(search) => navigate({ search: { search }, replace: true })}
+        />
+        <Suspense>
+          <Users search={search().search} />
+        </Suspense>
+      </Content>
+    </>
+  )
+}
+
+export const Route = createFileRoute({
+  validateSearch: v.object({
+    search: v.fallback(v.optional(v.string(), ''), ''),
+  }),
+  loaderDeps: (opt) => ({ search: opt.search }),
+  loader: (opt) => {
+    opt.context.queryClient.ensureQueryData(
+      usersQueryOptions(opt.deps.search.search),
+    )
+  },
+  component: Valibot,
+})
diff --git a/examples/solid/search-validator-adapters/src/routes/users/zod.index.tsx b/examples/solid/search-validator-adapters/src/routes/users/zod.index.tsx
new file mode 100644
index 0000000000..6c8654f291
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/routes/users/zod.index.tsx
@@ -0,0 +1,45 @@
+import { useNavigate } from '@tanstack/solid-router'
+import { fallback, zodValidator } from '@tanstack/zod-adapter'
+import { z } from 'zod'
+import { Suspense } from 'solid-js'
+import { Header } from '../../components/Header'
+import { Users, usersQueryOptions } from '../../components/Users'
+import { Content } from '../../components/Content'
+import { Search } from '../../components/Search'
+
+const Zod = () => {
+  const search = Route.useSearch({
+    select: (search) => search.search ?? '',
+  })
+  const navigate = useNavigate({ from: Route.fullPath })
+
+  return (
+    <>
+      <Header title="Zod" />
+      <Content>
+        <Search
+          search={search()}
+          onChange={(search) => navigate({ search: { search }, replace: true })}
+        />
+        <Suspense>
+          <Users search={search()} />
+        </Suspense>
+      </Content>
+    </>
+  )
+}
+
+export const Route = createFileRoute({
+  validateSearch: zodValidator(
+    z.object({
+      search: fallback(z.string().optional(), undefined),
+    }),
+  ),
+  loaderDeps: (opt) => ({ search: opt.search }),
+  loader: (opt) => {
+    opt.context.queryClient.ensureQueryData(
+      usersQueryOptions(opt.deps.search.search ?? ''),
+    )
+  },
+  component: Zod,
+})
diff --git a/examples/solid/search-validator-adapters/src/styles.css b/examples/solid/search-validator-adapters/src/styles.css
new file mode 100644
index 0000000000..37a1064738
--- /dev/null
+++ b/examples/solid/search-validator-adapters/src/styles.css
@@ -0,0 +1,21 @@
+@import 'tailwindcss';
+
+@layer base {
+  *,
+  ::after,
+  ::before,
+  ::backdrop,
+  ::file-selector-button {
+    border-color: var(--color-gray-200, currentcolor);
+  }
+}
+
+html {
+  color-scheme: light dark;
+}
+* {
+  @apply border-gray-200 dark:border-gray-800;
+}
+body {
+  @apply bg-gray-50 text-gray-950 dark:bg-gray-900 dark:text-gray-200;
+}
diff --git a/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx b/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
new file mode 100644
index 0000000000..29e0d3333f
--- /dev/null
+++ b/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
@@ -0,0 +1,16 @@
+import { Link } from '@tanstack/solid-router'
+import { expectTypeOf, test } from 'vitest'
+import { Route as ArkTypeRoute } from '../src/routes/users/arktype.index'
+import type { router } from '../src/main'
+
+test('infers correct input and output type for valibot', () => {
+  expectTypeOf(Link<typeof router, string, '/users/arktype'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<boolean | ((...args: ReadonlyArray<any>) => any)>()
+    .toEqualTypeOf<{ search?: string } | undefined>()
+
+  expectTypeOf(ArkTypeRoute.useSearch()).toEqualTypeOf<{
+    search: string
+  }>()
+})
diff --git a/examples/solid/search-validator-adapters/tests/arktype.test.tsx b/examples/solid/search-validator-adapters/tests/arktype.test.tsx
new file mode 100644
index 0000000000..71bef13f6f
--- /dev/null
+++ b/examples/solid/search-validator-adapters/tests/arktype.test.tsx
@@ -0,0 +1,64 @@
+import { fireEvent, render, screen } from '@solidjs/testing-library'
+import { expect, test } from 'vitest'
+import {
+  Link,
+  RouterProvider,
+  createRootRoute,
+  createRoute,
+  createRouter,
+} from '@tanstack/solid-router'
+
+import '@testing-library/jest-dom/vitest'
+import { type } from 'arktype'
+
+test('can navigate to the route', async () => {
+  const rootRoute = createRootRoute()
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: () => <Link to="/users/arktype">Arktype</Link>,
+  })
+
+  const ArkType = () => {
+    const search = arkTypeRoute.useSearch()
+
+    return (
+      <div>
+        <div>{search()}</div>
+        <Link from="/users/arktype" search={{ search: 'updated' }}>
+          Update
+        </Link>
+      </div>
+    )
+  }
+
+  const search = type({
+    search: 'string = "default"',
+  })
+
+  const arkTypeRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/users/arkType',
+    validateSearch: search,
+    component: ArkType,
+  })
+
+  const routeTree = rootRoute.addChildren([indexRoute, arkTypeRoute])
+
+  const router = createRouter({ routeTree, scrollRestoration: true })
+
+  render(() => <RouterProvider router={router as any} />)
+
+  const link = await screen.findByText('Arktype')
+
+  fireEvent.click(link)
+
+  expect(await screen.findByText('default')).toBeInTheDocument()
+
+  const updateLink = await screen.findByText('Update')
+
+  fireEvent.click(updateLink)
+
+  expect(await screen.findByText('updated')).toBeInTheDocument()
+})
diff --git a/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx b/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx
new file mode 100644
index 0000000000..a8a60c959c
--- /dev/null
+++ b/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx
@@ -0,0 +1,14 @@
+import { Link } from '@tanstack/solid-router'
+import { expectTypeOf, test } from 'vitest'
+import { Route as ValibotRoute } from '../src/routes/users/valibot.index'
+import type { router } from '../src/main'
+
+test('infers correct input and output type for valibot', () => {
+  expectTypeOf(Link<typeof router, string, '/users/valibot'>)
+    .parameter(0)
+    .toHaveProperty('search')
+    .exclude<boolean | ((...args: ReadonlyArray<any>) => any)>()
+    .toEqualTypeOf<{ search?: string } | undefined>()
+
+  expectTypeOf(ValibotRoute.useSearch()).toEqualTypeOf<{ search: string }>()
+})
diff --git a/examples/solid/search-validator-adapters/tests/valibot.test.tsx b/examples/solid/search-validator-adapters/tests/valibot.test.tsx
new file mode 100644
index 0000000000..d0ab289a38
--- /dev/null
+++ b/examples/solid/search-validator-adapters/tests/valibot.test.tsx
@@ -0,0 +1,61 @@
+import { fireEvent, render, screen } from '@solidjs/testing-library'
+import { expect, test } from 'vitest'
+import {
+  Link,
+  RouterProvider,
+  createRootRoute,
+  createRoute,
+  createRouter,
+} from '@tanstack/solid-router'
+import * as v from 'valibot'
+import '@testing-library/jest-dom/vitest'
+
+test('can navigate to the route', async () => {
+  const rootRoute = createRootRoute()
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    component: () => <Link to="/users/valibot">Valibot</Link>,
+  })
+
+  const Valibot = () => {
+    const search = valibotRoute.useSearch()
+
+    return (
+      <div>
+        <div>{search()}</div>
+        <Link from="/users/valibot" search={{ search: 'updated' }}>
+          Update
+        </Link>
+      </div>
+    )
+  }
+
+  const valibotRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/users/valibot',
+    validateSearch: v.object({
+      search: v.optional(v.string(), 'default'),
+    }),
+    component: Valibot,
+  })
+
+  const routeTree = rootRoute.addChildren([indexRoute, valibotRoute])
+
+  const router = createRouter({ routeTree, scrollRestoration: true })
+
+  render(() => <RouterProvider router={router as any} />)
+
+  const link = await screen.findByText('Valibot')
+
+  fireEvent.click(link)
+
+  expect(await screen.findByText('default')).toBeInTheDocument()
+
+  const updateLink = await screen.findByText('Update')
+
+  fireEvent.click(updateLink)
+
+  expect(await screen.findByText('updated')).toBeInTheDocument()
+})
diff --git a/examples/solid/search-validator-adapters/tsconfig.json b/examples/solid/search-validator-adapters/tsconfig.json
new file mode 100644
index 0000000000..ee3ff22c17
--- /dev/null
+++ b/examples/solid/search-validator-adapters/tsconfig.json
@@ -0,0 +1,13 @@
+{
+  "compilerOptions": {
+    "strict": true,
+    "esModuleInterop": true,
+    "jsx": "preserve",
+    "jsxImportSource": "solid-js",
+    "target": "ESNext",
+    "moduleResolution": "Bundler",
+    "module": "ESNext",
+    "skipLibCheck": true,
+    "lib": ["DOM", "DOM.Iterable", "ES2022"]
+  }
+}
diff --git a/examples/solid/search-validator-adapters/vite.config.ts b/examples/solid/search-validator-adapters/vite.config.ts
new file mode 100644
index 0000000000..0384779545
--- /dev/null
+++ b/examples/solid/search-validator-adapters/vite.config.ts
@@ -0,0 +1,22 @@
+import { defineConfig } from 'vitest/config'
+import solid from 'vite-plugin-solid'
+import { tanstackRouter } from '@tanstack/router-plugin/vite'
+import packageJson from './package.json'
+
+export default defineConfig({
+  test: {
+    name: packageJson.name,
+    dir: './tests',
+    watch: false,
+    environment: 'jsdom',
+    typecheck: { enabled: true },
+  },
+  plugins: [
+    tanstackRouter({
+      target: 'solid',
+      autoCodeSplitting: true,
+      verboseFileRoutes: false,
+    }),
+    solid(),
+  ],
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c42196d18e..a0667880c5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -7878,6 +7878,67 @@ importers:
         specifier: ^2.11.10
         version: 2.11.10(@testing-library/jest-dom@6.6.3)(solid-js@1.9.10)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
 
+  examples/solid/search-validator-adapters:
+    dependencies:
+      '@tailwindcss/postcss':
+        specifier: ^4.1.15
+        version: 4.1.15
+      '@tanstack/arktype-adapter':
+        specifier: workspace:*
+        version: link:../../../packages/arktype-adapter
+      '@tanstack/router-plugin':
+        specifier: workspace:*
+        version: link:../../../packages/router-plugin
+      '@tanstack/solid-query':
+        specifier: ^5.90.0
+        version: 5.90.9(solid-js@1.9.10)
+      '@tanstack/solid-router':
+        specifier: ^1.135.2
+        version: link:../../../packages/solid-router
+      '@tanstack/solid-router-devtools':
+        specifier: workspace:^
+        version: link:../../../packages/solid-router-devtools
+      '@tanstack/valibot-adapter':
+        specifier: workspace:*
+        version: link:../../../packages/valibot-adapter
+      '@tanstack/zod-adapter':
+        specifier: workspace:*
+        version: link:../../../packages/zod-adapter
+      arktype:
+        specifier: ^2.1.7
+        version: 2.1.7
+      postcss:
+        specifier: ^8.5.1
+        version: 8.5.6
+      solid-js:
+        specifier: 1.9.10
+        version: 1.9.10
+      tailwindcss:
+        specifier: ^4.1.15
+        version: 4.1.17
+      valibot:
+        specifier: 1.0.0-beta.15
+        version: 1.0.0-beta.15(typescript@5.9.2)
+      zod:
+        specifier: ^3.24.2
+        version: 3.25.57
+    devDependencies:
+      '@solidjs/testing-library':
+        specifier: ^0.8.10
+        version: 0.8.10(solid-js@1.9.10)
+      '@testing-library/jest-dom':
+        specifier: ^6.6.3
+        version: 6.6.3
+      typescript:
+        specifier: ^5.7.2
+        version: 5.9.2
+      vite:
+        specifier: ^7.1.7
+        version: 7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+      vite-plugin-solid:
+        specifier: ^2.11.10
+        version: 2.11.10(@testing-library/jest-dom@6.6.3)(solid-js@1.9.10)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+
   examples/solid/start-basic:
     dependencies:
       '@tanstack/solid-router':

From c0f482ad9c136c3bdeb51f72e6c882389e2ef13a Mon Sep 17 00:00:00 2001
From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com>
Date: Wed, 12 Nov 2025 20:03:08 +0000
Subject: [PATCH 2/6] ci: apply automated fixes

---
 examples/solid/search-validator-adapters/src/routes/__root.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/solid/search-validator-adapters/src/routes/__root.tsx b/examples/solid/search-validator-adapters/src/routes/__root.tsx
index 544efa185a..6666e5ba30 100644
--- a/examples/solid/search-validator-adapters/src/routes/__root.tsx
+++ b/examples/solid/search-validator-adapters/src/routes/__root.tsx
@@ -1,6 +1,6 @@
 import { Outlet, createRootRouteWithContext } from '@tanstack/solid-router'
 import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
-import type {QueryClient} from '@tanstack/solid-query';
+import type { QueryClient } from '@tanstack/solid-query'
 
 export interface Context {
   queryClient: QueryClient

From 97a7430dcdde916da84230e53b20ae7c2d31bac7 Mon Sep 17 00:00:00 2001
From: Birk Skyum <birk.skyum@pm.me>
Date: Wed, 12 Nov 2025 22:21:05 +0100
Subject: [PATCH 3/6] fix types

---
 .../search-validator-adapters/tests/arktype.test-d.tsx     | 5 +++--
 .../search-validator-adapters/tests/valibot.test-d.tsx     | 7 ++++++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx b/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
index 29e0d3333f..e375957a81 100644
--- a/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
+++ b/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
@@ -2,6 +2,7 @@ import { Link } from '@tanstack/solid-router'
 import { expectTypeOf, test } from 'vitest'
 import { Route as ArkTypeRoute } from '../src/routes/users/arktype.index'
 import type { router } from '../src/main'
+import type { Accessor } from 'solid-js'
 
 test('infers correct input and output type for valibot', () => {
   expectTypeOf(Link<typeof router, string, '/users/arktype'>)
@@ -10,7 +11,7 @@ test('infers correct input and output type for valibot', () => {
     .exclude<boolean | ((...args: ReadonlyArray<any>) => any)>()
     .toEqualTypeOf<{ search?: string } | undefined>()
 
-  expectTypeOf(ArkTypeRoute.useSearch()).toEqualTypeOf<{
+  expectTypeOf(ArkTypeRoute.useSearch()).toEqualTypeOf<Accessor<{
     search: string
-  }>()
+  }>>()
 })
diff --git a/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx b/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx
index a8a60c959c..50c6d47f53 100644
--- a/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx
+++ b/examples/solid/search-validator-adapters/tests/valibot.test-d.tsx
@@ -2,6 +2,7 @@ import { Link } from '@tanstack/solid-router'
 import { expectTypeOf, test } from 'vitest'
 import { Route as ValibotRoute } from '../src/routes/users/valibot.index'
 import type { router } from '../src/main'
+import type { Accessor } from 'solid-js'
 
 test('infers correct input and output type for valibot', () => {
   expectTypeOf(Link<typeof router, string, '/users/valibot'>)
@@ -10,5 +11,9 @@ test('infers correct input and output type for valibot', () => {
     .exclude<boolean | ((...args: ReadonlyArray<any>) => any)>()
     .toEqualTypeOf<{ search?: string } | undefined>()
 
-  expectTypeOf(ValibotRoute.useSearch()).toEqualTypeOf<{ search: string }>()
+  expectTypeOf(ValibotRoute.useSearch()).toEqualTypeOf<
+    Accessor<{
+      search: string
+    }>
+  >()
 })

From fb0212721af97212fa2747a1d106b47933f47718 Mon Sep 17 00:00:00 2001
From: Birk Skyum <birk.skyum@pm.me>
Date: Wed, 12 Nov 2025 22:21:29 +0100
Subject: [PATCH 4/6] format

---
 .../search-validator-adapters/tests/arktype.test-d.tsx    | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx b/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
index e375957a81..bb2f62b4ed 100644
--- a/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
+++ b/examples/solid/search-validator-adapters/tests/arktype.test-d.tsx
@@ -11,7 +11,9 @@ test('infers correct input and output type for valibot', () => {
     .exclude<boolean | ((...args: ReadonlyArray<any>) => any)>()
     .toEqualTypeOf<{ search?: string } | undefined>()
 
-  expectTypeOf(ArkTypeRoute.useSearch()).toEqualTypeOf<Accessor<{
-    search: string
-  }>>()
+  expectTypeOf(ArkTypeRoute.useSearch()).toEqualTypeOf<
+    Accessor<{
+      search: string
+    }>
+  >()
 })

From bb7e913a02633188f1a4512360298a3a03ec5482 Mon Sep 17 00:00:00 2001
From: Birk Skyum <birk.skyum@pm.me>
Date: Wed, 12 Nov 2025 22:32:34 +0100
Subject: [PATCH 5/6] fix unit test

---
 .../solid/search-validator-adapters/tests/arktype.test.tsx    | 4 ++--
 .../solid/search-validator-adapters/tests/valibot.test.tsx    | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/examples/solid/search-validator-adapters/tests/arktype.test.tsx b/examples/solid/search-validator-adapters/tests/arktype.test.tsx
index 71bef13f6f..7e130132bd 100644
--- a/examples/solid/search-validator-adapters/tests/arktype.test.tsx
+++ b/examples/solid/search-validator-adapters/tests/arktype.test.tsx
@@ -21,11 +21,11 @@ test('can navigate to the route', async () => {
   })
 
   const ArkType = () => {
-    const search = arkTypeRoute.useSearch()
+    const search = arkTypeRoute.useSearch() as () => { search: string }
 
     return (
       <div>
-        <div>{search()}</div>
+        <div>{search().search}</div>
         <Link from="/users/arktype" search={{ search: 'updated' }}>
           Update
         </Link>
diff --git a/examples/solid/search-validator-adapters/tests/valibot.test.tsx b/examples/solid/search-validator-adapters/tests/valibot.test.tsx
index d0ab289a38..882a73d574 100644
--- a/examples/solid/search-validator-adapters/tests/valibot.test.tsx
+++ b/examples/solid/search-validator-adapters/tests/valibot.test.tsx
@@ -20,11 +20,11 @@ test('can navigate to the route', async () => {
   })
 
   const Valibot = () => {
-    const search = valibotRoute.useSearch()
+    const search = valibotRoute.useSearch() as () => { search: string }
 
     return (
       <div>
-        <div>{search()}</div>
+        <div>{search().search}</div>
         <Link from="/users/valibot" search={{ search: 'updated' }}>
           Update
         </Link>

From ddaced694977543f3f272c2b0e4eba74b037c14a Mon Sep 17 00:00:00 2001
From: Birk Skyum <birk.skyum@pm.me>
Date: Wed, 12 Nov 2025 22:46:35 +0100
Subject: [PATCH 6/6] use searhc params directly

---
 .../src/routes/users/arktype.index.tsx                    | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx b/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx
index 6db9bb826d..cd31ae9955 100644
--- a/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx
+++ b/examples/solid/search-validator-adapters/src/routes/users/arktype.index.tsx
@@ -7,9 +7,7 @@ import { Content } from '../../components/Content'
 import { Search } from '../../components/Search'
 
 const ArkType = () => {
-  const search = Route.useSearch({
-    select: (search) => search.search,
-  })
+  const search = Route.useSearch()
   const navigate = useNavigate({ from: Route.fullPath })
 
   return (
@@ -17,11 +15,11 @@ const ArkType = () => {
       <Header title="ArkType" />
       <Content>
         <Search
-          search={search()}
+          search={search().search}
           onChange={(search) => navigate({ search: { search }, replace: true })}
         />
         <Suspense>
-          <Users search={search()} />
+          <Users search={search().search} />
         </Suspense>
       </Content>
     </>
