diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 987cb212f9..0bcc5479d4 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -30,6 +30,7 @@ jobs:
"examples/inspector",
"examples/music-player",
"examples/organization",
+ "examples/tanstack-form",
"starters/react-passkey-auth",
"starters/svelte-passkey-auth",
"tests/jazz-svelte"
diff --git a/examples/tanstack-form/.gitignore b/examples/tanstack-form/.gitignore
new file mode 100644
index 0000000000..576212b70b
--- /dev/null
+++ b/examples/tanstack-form/.gitignore
@@ -0,0 +1,33 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+/test-results/
+/playwright-report/
+
+# env files
+.env
+.env.*
+!.env.example
+!.env.test
diff --git a/examples/tanstack-form/CHANGELOG.md b/examples/tanstack-form/CHANGELOG.md
new file mode 100644
index 0000000000..b540e82eed
--- /dev/null
+++ b/examples/tanstack-form/CHANGELOG.md
@@ -0,0 +1,858 @@
+# form
+
+## 0.1.60
+
+### Patch Changes
+
+- Updated dependencies [048ac1d]
+ - jazz-tools@0.14.22
+ - jazz-react@0.14.22
+
+## 0.1.59
+
+### Patch Changes
+
+- Updated dependencies [e7e505e]
+- Updated dependencies [13b57aa]
+- Updated dependencies [5662faa]
+- Updated dependencies [2116a59]
+ - jazz-tools@0.14.21
+ - jazz-react@0.14.21
+
+## 0.1.58
+
+### Patch Changes
+
+- Updated dependencies [6f72419]
+- Updated dependencies [04b20c2]
+ - jazz-tools@0.14.20
+ - jazz-react@0.14.20
+
+## 0.1.57
+
+### Patch Changes
+
+- jazz-react@0.14.19
+- jazz-tools@0.14.19
+
+## 0.1.56
+
+### Patch Changes
+
+- Updated dependencies [4b950bc]
+- Updated dependencies [d6d9c0a]
+- Updated dependencies [c559054]
+ - jazz-tools@0.14.18
+ - jazz-react@0.14.18
+
+## 0.1.55
+
+### Patch Changes
+
+- Updated dependencies [e512df4]
+ - jazz-tools@0.14.17
+ - jazz-react@0.14.17
+
+## 0.1.54
+
+### Patch Changes
+
+- jazz-react@0.14.16
+- jazz-tools@0.14.16
+
+## 0.1.53
+
+### Patch Changes
+
+- Updated dependencies [f9590f9]
+ - jazz-react@0.14.15
+ - jazz-tools@0.14.15
+
+## 0.1.52
+
+### Patch Changes
+
+- Updated dependencies [e32a1f7]
+ - jazz-tools@0.14.14
+ - jazz-react@0.14.14
+
+## 0.1.51
+
+### Patch Changes
+
+- jazz-react@0.14.13
+
+## 0.1.50
+
+### Patch Changes
+
+- jazz-react@0.14.12
+
+## 0.1.49
+
+### Patch Changes
+
+- Updated dependencies [dc746a2]
+- Updated dependencies [f869d9a]
+- Updated dependencies [3fe6832]
+ - hash-slash@0.2.3
+ - jazz-react@0.14.10
+ - jazz-tools@0.14.10
+
+## 0.1.48
+
+### Patch Changes
+
+- Updated dependencies [22c2600]
+ - jazz-tools@0.14.9
+ - jazz-react@0.14.9
+
+## 0.1.47
+
+### Patch Changes
+
+- Updated dependencies [637ae13]
+ - jazz-tools@0.14.8
+ - jazz-react@0.14.8
+
+## 0.1.46
+
+### Patch Changes
+
+- Updated dependencies [365b0ea]
+ - jazz-tools@0.14.7
+ - jazz-react@0.14.7
+
+## 0.1.45
+
+### Patch Changes
+
+- Updated dependencies [9d6d9fe]
+- Updated dependencies [9d6d9fe]
+ - jazz-tools@0.14.6
+ - jazz-react@0.14.6
+
+## 0.1.44
+
+### Patch Changes
+
+- Updated dependencies [91cbb2f]
+- Updated dependencies [20b3d88]
+ - jazz-tools@0.14.5
+ - jazz-react@0.14.5
+
+## 0.1.43
+
+### Patch Changes
+
+- Updated dependencies [011af55]
+ - jazz-tools@0.14.4
+ - jazz-react@0.14.4
+
+## 0.1.42
+
+### Patch Changes
+
+- Updated dependencies [3d1027f]
+- Updated dependencies [c240eed]
+ - jazz-tools@0.14.2
+ - jazz-react@0.14.2
+
+## 0.1.41
+
+### Patch Changes
+
+- Updated dependencies [cdfc105]
+ - jazz-tools@0.14.1
+ - jazz-react@0.14.1
+
+## 0.1.40
+
+### Patch Changes
+
+- Updated dependencies [5835ed1]
+ - jazz-tools@0.14.0
+ - jazz-react@0.14.0
+
+## 0.1.39
+
+### Patch Changes
+
+- jazz-react@0.13.32
+
+## 0.1.38
+
+### Patch Changes
+
+- Updated dependencies [e5b170f]
+ - jazz-tools@0.13.31
+ - jazz-react@0.13.31
+
+## 0.1.37
+
+### Patch Changes
+
+- jazz-react@0.13.30
+- jazz-tools@0.13.30
+
+## 0.1.36
+
+### Patch Changes
+
+- jazz-react@0.13.29
+- jazz-tools@0.13.29
+
+## 0.1.35
+
+### Patch Changes
+
+- jazz-react@0.13.28
+- jazz-tools@0.13.28
+
+## 0.1.34
+
+### Patch Changes
+
+- jazz-react@0.13.27
+- jazz-tools@0.13.27
+
+## 0.1.33
+
+### Patch Changes
+
+- Updated dependencies [ff846d9]
+ - jazz-tools@0.13.26
+ - jazz-react@0.13.26
+
+## 0.1.32
+
+### Patch Changes
+
+- jazz-react@0.13.25
+- jazz-tools@0.13.25
+
+## 0.1.31
+
+### Patch Changes
+
+- Updated dependencies [02a240c]
+ - jazz-tools@0.13.23
+ - jazz-react@0.13.23
+
+## 0.1.30
+
+### Patch Changes
+
+- jazz-react@0.13.21
+- jazz-tools@0.13.21
+
+## 0.1.29
+
+### Patch Changes
+
+- Updated dependencies [439f0fe]
+ - jazz-tools@0.13.20
+ - jazz-react@0.13.20
+
+## 0.1.28
+
+### Patch Changes
+
+- Updated dependencies [80530a4]
+ - jazz-tools@0.13.19
+ - jazz-react@0.13.19
+
+## 0.1.27
+
+### Patch Changes
+
+- Updated dependencies [761759c]
+ - jazz-tools@0.13.18
+ - jazz-react@0.13.18
+
+## 0.1.26
+
+### Patch Changes
+
+- jazz-react@0.13.17
+- jazz-tools@0.13.17
+
+## 0.1.25
+
+### Patch Changes
+
+- jazz-react@0.13.16
+- jazz-tools@0.13.16
+
+## 0.1.24
+
+### Patch Changes
+
+- jazz-react@0.13.15
+- jazz-tools@0.13.15
+
+## 0.1.23
+
+### Patch Changes
+
+- jazz-react@0.13.14
+- jazz-tools@0.13.14
+
+## 0.1.22
+
+### Patch Changes
+
+- jazz-react@0.13.13
+- jazz-tools@0.13.13
+
+## 0.1.21
+
+### Patch Changes
+
+- Updated dependencies [4547525]
+ - jazz-tools@0.13.12
+ - jazz-react@0.13.12
+
+## 0.1.20
+
+### Patch Changes
+
+- Updated dependencies [17273a6]
+ - jazz-tools@0.13.11
+ - jazz-react@0.13.11
+
+## 0.1.19
+
+### Patch Changes
+
+- jazz-react@0.13.10
+- jazz-tools@0.13.10
+
+## 0.1.18
+
+### Patch Changes
+
+- Updated dependencies [a6cf01f]
+ - jazz-tools@0.13.9
+ - jazz-react@0.13.9
+
+## 0.1.17
+
+### Patch Changes
+
+- Updated dependencies [bc3d7bb]
+ - jazz-tools@0.13.7
+ - jazz-react@0.13.7
+
+## 0.1.16
+
+### Patch Changes
+
+- Updated dependencies [fe6f561]
+ - jazz-tools@0.13.5
+ - jazz-react@0.13.5
+
+## 0.1.15
+
+### Patch Changes
+
+- Updated dependencies [3129982]
+ - jazz-react@0.13.4
+ - jazz-tools@0.13.4
+
+## 0.1.14
+
+### Patch Changes
+
+- Updated dependencies [12f8bfa]
+- Updated dependencies [bd57177]
+ - jazz-tools@0.13.3
+ - jazz-react@0.13.3
+
+## 0.1.13
+
+### Patch Changes
+
+- jazz-react@0.13.2
+- jazz-tools@0.13.2
+
+## 0.1.12
+
+### Patch Changes
+
+- Updated dependencies [afd1374]
+ - jazz-tools@0.13.0
+ - jazz-react@0.13.0
+
+## 0.1.11
+
+### Patch Changes
+
+- jazz-react@0.12.2
+- jazz-tools@0.12.2
+
+## 0.1.10
+
+### Patch Changes
+
+- jazz-react@0.12.1
+- jazz-tools@0.12.1
+
+## 0.1.9
+
+### Patch Changes
+
+- Updated dependencies [01523dc]
+- Updated dependencies [4ea87dc]
+- Updated dependencies [1e6da19]
+- Updated dependencies [b6c6a0a]
+ - jazz-tools@0.12.0
+ - jazz-react@0.12.0
+
+## 0.1.8
+
+### Patch Changes
+
+- jazz-react@0.11.8
+- jazz-tools@0.11.8
+
+## 0.1.7
+
+### Patch Changes
+
+- Updated dependencies [a140f55]
+- Updated dependencies [4019918]
+- Updated dependencies [2b0d1b0]
+ - jazz-tools@0.11.7
+ - jazz-react@0.11.7
+
+## 0.1.6
+
+### Patch Changes
+
+- Updated dependencies [e7c85b7]
+- Updated dependencies [8ed144e]
+ - jazz-react@0.11.6
+ - jazz-tools@0.11.6
+ - jazz-browser-media-images@0.11.6
+
+## 0.1.5
+
+### Patch Changes
+
+- jazz-react@0.11.5
+- jazz-tools@0.11.5
+- jazz-browser-media-images@0.11.5
+
+## 0.1.4
+
+### Patch Changes
+
+- Updated dependencies [57a3dbe]
+- Updated dependencies [a717754]
+- Updated dependencies [a91f343]
+ - jazz-tools@0.11.4
+ - jazz-browser-media-images@0.11.4
+ - jazz-react@0.11.4
+
+## 0.1.3
+
+### Patch Changes
+
+- jazz-react@0.11.3
+- jazz-tools@0.11.3
+- jazz-browser-media-images@0.11.3
+
+## 0.1.2
+
+### Patch Changes
+
+- Updated dependencies [6892dc6]
+ - jazz-tools@0.11.2
+ - jazz-react@0.11.2
+ - jazz-browser-media-images@0.11.2
+
+## 0.1.1
+
+### Patch Changes
+
+- jazz-react@0.11.1
+
+## 0.1.0
+
+### Minor Changes
+
+- 18428ea: PasskeyAuth: Sets `profile.name` only if a non-empty username is passed to `signUp`
+
+### Patch Changes
+
+- Updated dependencies [6a96d8b]
+- Updated dependencies [a35249a]
+- Updated dependencies [b9d194a]
+- Updated dependencies [a4713df]
+- Updated dependencies [34cbdc3]
+- Updated dependencies [f039e8f]
+- Updated dependencies [e22de9f]
+ - jazz-tools@0.11.0
+ - jazz-browser-media-images@0.11.0
+ - jazz-react@0.11.0
+
+## 0.0.53
+
+### Patch Changes
+
+- Updated dependencies [2f99de0]
+ - jazz-tools@0.10.15
+ - jazz-browser-media-images@0.10.15
+ - jazz-react@0.10.15
+
+## 0.0.52
+
+### Patch Changes
+
+- Updated dependencies [75211e3]
+ - jazz-tools@0.10.14
+ - jazz-react@0.10.14
+ - jazz-browser-media-images@0.10.14
+
+## 0.0.51
+
+### Patch Changes
+
+- Updated dependencies [07feedd]
+ - jazz-tools@0.10.13
+ - jazz-browser-media-images@0.10.13
+ - jazz-react@0.10.13
+
+## 0.0.50
+
+### Patch Changes
+
+- Updated dependencies [4612e05]
+ - jazz-tools@0.10.12
+ - jazz-react@0.10.12
+ - jazz-browser-media-images@0.10.12
+
+## 0.0.49
+
+### Patch Changes
+
+- jazz-browser-media-images@0.10.9
+- jazz-react@0.10.9
+
+## 0.0.48
+
+### Patch Changes
+
+- Updated dependencies [2fb6428]
+ - jazz-tools@0.10.8
+ - jazz-react@0.10.8
+ - jazz-browser-media-images@0.10.8
+
+## 0.0.47
+
+### Patch Changes
+
+- Updated dependencies [1136d9b]
+- Updated dependencies [0eed228]
+ - jazz-react@0.10.7
+ - jazz-tools@0.10.7
+ - jazz-browser-media-images@0.10.7
+
+## 0.0.46
+
+### Patch Changes
+
+- Updated dependencies [1d71ca1]
+- Updated dependencies [ada802b]
+ - hash-slash@0.2.2
+ - jazz-react@0.10.6
+ - jazz-tools@0.10.6
+ - jazz-browser-media-images@0.10.6
+
+## 0.0.45
+
+### Patch Changes
+
+- Updated dependencies [59ff77e]
+ - jazz-tools@0.10.5
+ - jazz-browser-media-images@0.10.5
+ - jazz-react@0.10.5
+
+## 0.0.44
+
+### Patch Changes
+
+- jazz-react@0.10.4
+- jazz-tools@0.10.4
+- jazz-browser-media-images@0.10.4
+
+## 0.0.43
+
+### Patch Changes
+
+- Updated dependencies [d8582fc]
+ - jazz-tools@0.10.3
+ - jazz-browser-media-images@0.10.3
+ - jazz-react@0.10.3
+
+## 0.0.42
+
+### Patch Changes
+
+- jazz-react@0.10.2
+- jazz-tools@0.10.2
+- jazz-browser-media-images@0.10.2
+
+## 0.0.41
+
+### Patch Changes
+
+- Updated dependencies [5a63cba]
+ - jazz-tools@0.10.1
+ - jazz-browser-media-images@0.10.1
+ - jazz-react@0.10.1
+
+## 0.0.40
+
+### Patch Changes
+
+- Updated dependencies [498954f]
+- Updated dependencies [d42c2aa]
+- Updated dependencies [dd03464]
+- Updated dependencies [b426342]
+ - jazz-react@0.10.0
+ - jazz-tools@0.10.0
+ - jazz-browser-media-images@0.10.0
+
+## 0.0.39
+
+### Patch Changes
+
+- jazz-react@0.9.23
+- jazz-tools@0.9.23
+- jazz-browser-media-images@0.9.23
+
+## 0.0.38
+
+### Patch Changes
+
+- jazz-browser-media-images@0.9.22
+- jazz-react@0.9.22
+
+## 0.0.37
+
+### Patch Changes
+
+- Updated dependencies [1be017d]
+ - jazz-tools@0.9.21
+ - jazz-browser-media-images@0.9.21
+ - jazz-react@0.9.21
+
+## 0.0.36
+
+### Patch Changes
+
+- Updated dependencies [b01cc1f]
+ - jazz-tools@0.9.20
+ - jazz-browser-media-images@0.9.20
+ - jazz-react@0.9.20
+
+## 0.0.35
+
+### Patch Changes
+
+- jazz-react@0.9.19
+- jazz-tools@0.9.19
+- jazz-browser-media-images@0.9.19
+
+## 0.0.34
+
+### Patch Changes
+
+- jazz-react@0.9.18
+- jazz-tools@0.9.18
+- jazz-browser-media-images@0.9.18
+
+## 0.0.33
+
+### Patch Changes
+
+- Updated dependencies [c2ca1fe]
+- Updated dependencies [1227047]
+ - jazz-tools@0.9.17
+ - jazz-browser-media-images@0.9.17
+ - jazz-react@0.9.17
+
+## 0.0.32
+
+### Patch Changes
+
+- Updated dependencies [24b3b6a]
+ - jazz-tools@0.9.16
+ - jazz-browser-media-images@0.9.16
+ - jazz-react@0.9.16
+
+## 0.0.31
+
+### Patch Changes
+
+- Updated dependencies [7491711]
+ - jazz-tools@0.9.15
+ - jazz-browser-media-images@0.9.15
+ - jazz-react@0.9.15
+
+## 0.0.30
+
+### Patch Changes
+
+- Updated dependencies [3df93cc]
+ - jazz-tools@0.9.14
+ - jazz-browser-media-images@0.9.14
+ - jazz-react@0.9.14
+
+## 0.0.29
+
+### Patch Changes
+
+- jazz-react@0.9.13
+- jazz-tools@0.9.13
+- jazz-browser-media-images@0.9.13
+
+## 0.0.28
+
+### Patch Changes
+
+- jazz-react@0.9.12
+- jazz-tools@0.9.12
+- jazz-browser-media-images@0.9.12
+
+## 0.0.27
+
+### Patch Changes
+
+- jazz-react@0.9.11
+- jazz-tools@0.9.11
+- jazz-browser-media-images@0.9.11
+
+## 0.0.26
+
+### Patch Changes
+
+- Updated dependencies [5e83864]
+ - jazz-react@0.9.10
+ - jazz-tools@0.9.10
+ - jazz-browser-media-images@0.9.10
+
+## 0.0.25
+
+### Patch Changes
+
+- Updated dependencies [8eb9247]
+ - jazz-tools@0.9.9
+ - jazz-browser-media-images@0.9.9
+ - jazz-react@0.9.9
+
+## 0.0.24
+
+### Patch Changes
+
+- Updated dependencies [d1d773b]
+ - jazz-tools@0.9.8
+ - jazz-react@0.9.8
+ - jazz-browser-media-images@0.9.8
+
+## 0.0.23
+
+### Patch Changes
+
+- jazz-react@0.9.4
+
+## 0.0.22
+
+### Patch Changes
+
+- Updated dependencies [1b71969]
+ - jazz-react@0.9.1
+ - jazz-tools@0.9.1
+ - jazz-browser-media-images@0.9.1
+
+## 0.0.21
+
+### Patch Changes
+
+- Updated dependencies [956a4d1]
+- Updated dependencies [8eda792]
+ - jazz-react@0.9.0
+ - jazz-tools@0.9.0
+ - jazz-browser-media-images@0.9.0
+
+## 0.0.20
+
+### Patch Changes
+
+- Updated dependencies [dc62b95]
+- Updated dependencies [1de26f8]
+ - jazz-tools@0.8.51
+ - jazz-browser-media-images@0.8.51
+ - jazz-react@0.8.51
+
+## 0.0.19
+
+### Patch Changes
+
+- jazz-react@0.8.50
+- jazz-tools@0.8.50
+- jazz-browser-media-images@0.8.50
+
+## 0.0.18
+
+### Patch Changes
+
+- jazz-react@0.8.49
+- jazz-tools@0.8.49
+- jazz-browser-media-images@0.8.49
+
+## 0.0.17
+
+### Patch Changes
+
+- Updated dependencies [635e824]
+- Updated dependencies [0a85982]
+ - jazz-tools@0.8.48
+ - jazz-browser-media-images@0.8.48
+ - jazz-react@0.8.48
+
+## 0.0.16
+
+### Patch Changes
+
+- Updated dependencies [fa41f8e]
+- Updated dependencies [88d7d9a]
+- Updated dependencies [60e35ea]
+ - jazz-tools@0.8.45
+ - jazz-react@0.8.45
+ - jazz-browser-media-images@0.8.45
+
+## 0.0.15
+
+### Patch Changes
+
+- jazz-react@0.8.44
+- jazz-tools@0.8.44
+- jazz-browser-media-images@0.8.44
+
+## 0.0.14
+
+### Patch Changes
+
+- jazz-react@0.8.41
+- jazz-tools@0.8.41
+- jazz-browser-media-images@0.8.41
+
+## 0.0.13
+
+### Patch Changes
+
+- jazz-browser-media-images@0.8.40
+- jazz-react@0.8.40
diff --git a/examples/tanstack-form/README.md b/examples/tanstack-form/README.md
new file mode 100644
index 0000000000..46b1edafb2
--- /dev/null
+++ b/examples/tanstack-form/README.md
@@ -0,0 +1,69 @@
+# Form example with Jazz and TanStack Form
+
+This is a simple form example that shows you how to make a form for creating and editing a `CoValue`,
+called `BubbleTeaOrder`, with fields of different types such
+as single-select, multi-select, date, text, and boolean.
+
+The form is built using [TanStack Form](https://tanstack.com/form/). We leverage TanStack Form's
+support for [schema validation libraries](https://tanstack.com/form/latest/docs/framework/react/guides/validation#standard-schema-libraries)
+and validate the form using Jazz's Zod-based schemas.
+
+## Getting started
+
+You can either
+1. Clone the jazz repository, and run the app within the monorepo.
+2. Or create a new Jazz project using this example as a template.
+
+
+### Using the example as a template
+
+Create a new Jazz project, and use this example as a template.
+```bash
+npx create-jazz-app@latest form-app --example tanstack-form
+```
+
+Go to the new project directory.
+```bash
+cd form-app
+```
+
+Run the dev server.
+```bash
+npm run dev
+```
+
+### Using the monorepo
+
+This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
+
+Clone the jazz repository.
+```bash
+git clone https://github.com/garden-co/jazz.git
+```
+
+Install and build dependencies.
+```bash
+pnpm i && npx turbo build
+```
+
+Go to the example directory.
+```bash
+cd jazz/examples/tanstack-form/
+```
+
+Start the dev server.
+```bash
+pnpm dev
+```
+
+Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.
+
+## Questions / problems / feedback
+
+If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
+
+## Configuration: sync server
+
+By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
+
+You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzReactProvider` in [./src/main.tsx](./src/main.tsx) to `{ peer: "ws://localhost:4200" }`.
diff --git a/examples/tanstack-form/index.html b/examples/tanstack-form/index.html
new file mode 100644
index 0000000000..547077c4c4
--- /dev/null
+++ b/examples/tanstack-form/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Jazz | Form example
+
+
+
+
+
+
diff --git a/examples/tanstack-form/package.json b/examples/tanstack-form/package.json
new file mode 100644
index 0000000000..c8cda1b49f
--- /dev/null
+++ b/examples/tanstack-form/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "tanstack-form",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "check": "tsc --noEmit",
+ "preview": "vite preview",
+ "format-and-lint": "biome check .",
+ "format-and-lint:fix": "biome check . --write"
+ },
+ "dependencies": {
+ "@tanstack/react-form": "^1.0.0",
+ "hash-slash": "workspace:*",
+ "jazz-tools": "workspace:*",
+ "react": "19.0.0",
+ "react-dom": "19.0.0"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "1.9.4",
+ "@playwright/test": "^1.50.1",
+ "@tailwindcss/forms": "^0.5.10",
+ "@tailwindcss/postcss": "^4.1.10",
+ "@types/react": "19.0.0",
+ "@types/react-dom": "19.0.0",
+ "@vitejs/plugin-react": "^4.5.1",
+ "globals": "^15.11.0",
+ "is-ci": "^3.0.1",
+ "postcss": "^8.4.40",
+ "tailwindcss": "^4.1.10",
+ "typescript": "5.6.2",
+ "vite": "^6.3.5"
+ }
+}
diff --git a/examples/tanstack-form/playwright.config.ts b/examples/tanstack-form/playwright.config.ts
new file mode 100644
index 0000000000..ecb4f4f255
--- /dev/null
+++ b/examples/tanstack-form/playwright.config.ts
@@ -0,0 +1,46 @@
+import { defineConfig, devices } from "@playwright/test";
+import isCI from "is-ci";
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ testDir: "./tests",
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: isCI,
+ /* Retry on CI only */
+ retries: isCI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: isCI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: "html",
+
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: "http://localhost:5173/",
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: "on-first-retry",
+ permissions: ["clipboard-read", "clipboard-write"],
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: "chromium",
+ use: { ...devices["Desktop Chrome"] },
+ },
+ ],
+
+ /* Run your local dev server before starting the tests */
+ webServer: [
+ {
+ command: "pnpm preview --port 5173",
+ url: "http://localhost:5173/",
+ reuseExistingServer: !isCI,
+ },
+ ],
+});
diff --git a/examples/tanstack-form/postcss.config.js b/examples/tanstack-form/postcss.config.js
new file mode 100644
index 0000000000..c2ddf74822
--- /dev/null
+++ b/examples/tanstack-form/postcss.config.js
@@ -0,0 +1,5 @@
+export default {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ },
+};
diff --git a/examples/tanstack-form/public/favicon.ico b/examples/tanstack-form/public/favicon.ico
new file mode 100644
index 0000000000..799e937cd6
Binary files /dev/null and b/examples/tanstack-form/public/favicon.ico differ
diff --git a/examples/tanstack-form/src/App.tsx b/examples/tanstack-form/src/App.tsx
new file mode 100644
index 0000000000..fda85ad03b
--- /dev/null
+++ b/examples/tanstack-form/src/App.tsx
@@ -0,0 +1,22 @@
+import { useIframeHashRouter } from "hash-slash";
+import { CreateOrder } from "./CreateOrder.tsx";
+import { EditOrder } from "./EditOrder.tsx";
+import { Orders } from "./Orders.tsx";
+
+function App() {
+ const router = useIframeHashRouter();
+
+ return (
+ <>
+
+ {router.route({
+ "/": () => ,
+ "/order": () => ,
+ "/order/:id": (id) => ,
+ })}
+
+ >
+ );
+}
+
+export default App;
diff --git a/examples/tanstack-form/src/CreateOrder.tsx b/examples/tanstack-form/src/CreateOrder.tsx
new file mode 100644
index 0000000000..bde7c725a0
--- /dev/null
+++ b/examples/tanstack-form/src/CreateOrder.tsx
@@ -0,0 +1,53 @@
+import { useIframeHashRouter } from "hash-slash";
+import { CoPlainText } from "jazz-tools";
+import { useAccount } from "jazz-tools/react";
+import { LinkToHome } from "./LinkToHome.tsx";
+import { OrderForm, OrderFormData } from "./OrderForm.tsx";
+import {
+ BubbleTeaOrder,
+ JazzAccount,
+ ListOfBubbleTeaAddOns,
+} from "./schema.ts";
+
+export function CreateOrder() {
+ const { me } = useAccount(JazzAccount, {
+ resolve: { root: { orders: true } },
+ });
+ const router = useIframeHashRouter();
+
+ if (!me?.root) return;
+
+ const addOrder = (draft: OrderFormData) => {
+ const newOrder = BubbleTeaOrder.create({
+ baseTea: draft.baseTea,
+ deliveryDate: draft.deliveryDate,
+ withMilk: draft.withMilk,
+ addOns: ListOfBubbleTeaAddOns.create(draft.addOns),
+ instructions: draft.instructions
+ ? CoPlainText.create(draft.instructions)
+ : undefined,
+ });
+
+ me.root.orders.push(newOrder);
+
+ router.navigate("/");
+ };
+
+ const draftOrder: Partial = {
+ baseTea: "Black",
+ addOns: [],
+ withMilk: false,
+ };
+
+ return (
+ <>
+
+
+
+ Make a new bubble tea order 🧋
+
+
+
+ >
+ );
+}
diff --git a/examples/tanstack-form/src/EditOrder.tsx b/examples/tanstack-form/src/EditOrder.tsx
new file mode 100644
index 0000000000..edf4b4d45e
--- /dev/null
+++ b/examples/tanstack-form/src/EditOrder.tsx
@@ -0,0 +1,59 @@
+import { CoPlainText, Loaded } from "jazz-tools";
+import { useCoState } from "jazz-tools/react";
+import { LinkToHome } from "./LinkToHome.tsx";
+import { OrderForm, OrderFormData } from "./OrderForm.tsx";
+import { OrderThumbnail } from "./OrderThumbnail.tsx";
+import { BubbleTeaOrder } from "./schema.ts";
+
+export type LoadedBubbleTeaOrder = Loaded<
+ typeof BubbleTeaOrder,
+ { addOns: { $each: true }; instructions: true }
+>;
+
+export function EditOrder(props: { id: string }) {
+ const order = useCoState(BubbleTeaOrder, props.id, {
+ resolve: { addOns: true, instructions: true },
+ });
+
+ if (!order) return;
+
+ const onSubmit = (updatedOrder: OrderFormData) => {
+ // Apply changes to the original Jazz order
+ order.baseTea = updatedOrder.baseTea;
+ order.deliveryDate = updatedOrder.deliveryDate;
+ order.withMilk = updatedOrder.withMilk;
+ order.addOns.applyDiff(updatedOrder.addOns);
+
+ // `applyDiff` requires nested objects to be CoValues as well
+ order.instructions ??= CoPlainText.create("");
+ if (updatedOrder.instructions) {
+ order.instructions.applyDiff(updatedOrder.instructions);
+ }
+ };
+
+ const originalOrder: OrderFormData = order.toJSON();
+ // Convert timestamp to Date
+ originalOrder.deliveryDate = new Date(originalOrder.deliveryDate);
+
+ return (
+ <>
+
+
+
+
+
+ Edit your bubble tea order 🧋
+
+
+
+ >
+ );
+}
diff --git a/examples/tanstack-form/src/LinkToHome.tsx b/examples/tanstack-form/src/LinkToHome.tsx
new file mode 100644
index 0000000000..fc6c69a4b7
--- /dev/null
+++ b/examples/tanstack-form/src/LinkToHome.tsx
@@ -0,0 +1,7 @@
+export function LinkToHome() {
+ return (
+
+ < Back to all orders
+
+ );
+}
diff --git a/examples/tanstack-form/src/OrderForm.tsx b/examples/tanstack-form/src/OrderForm.tsx
new file mode 100644
index 0000000000..2722bac195
--- /dev/null
+++ b/examples/tanstack-form/src/OrderForm.tsx
@@ -0,0 +1,210 @@
+import { useForm } from "@tanstack/react-form";
+import { z } from "jazz-tools";
+import { OrderThumbnail } from "./OrderThumbnail.tsx";
+import {
+ BubbleTeaAddOnTypes,
+ BubbleTeaBaseTeaTypes,
+ BubbleTeaOrder,
+} from "./schema.ts";
+
+// TanStack Form can leverage Jazz's Zod schema to validate the form
+const orderZodSchemaShape = BubbleTeaOrder.getZodSchema().shape;
+const orderFormSchema = z.object({
+ ...orderZodSchemaShape,
+ baseTea: orderZodSchemaShape.baseTea.refine((value) => value, {
+ error: "Please select your preferred base tea.",
+ }),
+ deliveryDate: z.date("Plese select a delivery date."),
+ // TanStack Form doesn't support CoList fields, so we need to convert them to arrays
+ addOns: z
+ .array(z.enum(BubbleTeaAddOnTypes))
+ .min(1, "Please select at least one add-on."),
+ // TanStack Form doesn't support CoPlainText fields, so we need to convert them to strings
+ instructions: z.string().optional(),
+});
+
+export type OrderFormData = z.infer;
+
+export function OrderForm({
+ order: originalOrder,
+ onSubmit,
+ validateOn,
+}: {
+ order: Partial;
+ onSubmit: (order: OrderFormData) => void;
+ validateOn: "submit" | "change";
+}) {
+ const form = useForm({
+ defaultValues: originalOrder,
+ validators: {
+ onSubmit: validateOn === "submit" ? orderFormSchema : undefined,
+ onChange: validateOn === "change" ? orderFormSchema : undefined,
+ },
+ onSubmit: ({ value }) => {
+ // If the form is not valid according to orderFormSchema, the value will not be submitted
+ onSubmit(value as OrderFormData);
+ },
+ });
+
+ return (
+ [state.canSubmit, state.isSubmitting]}
+ children={([canSubmit, isSubmitting]) => (
+
+ )}
+ />
+
+ );
+}
diff --git a/examples/tanstack-form/src/OrderThumbnail.tsx b/examples/tanstack-form/src/OrderThumbnail.tsx
new file mode 100644
index 0000000000..c0380bcbd1
--- /dev/null
+++ b/examples/tanstack-form/src/OrderThumbnail.tsx
@@ -0,0 +1,36 @@
+import { Loaded } from "jazz-tools";
+import { OrderFormData } from "./OrderForm.tsx";
+import { BubbleTeaOrder } from "./schema.ts";
+
+export function OrderThumbnail({
+ order,
+}: {
+ order: Loaded | Partial;
+}) {
+ const { baseTea, addOns, instructions, deliveryDate, withMilk } = order;
+ const date = deliveryDate?.toLocaleDateString("en-US", {
+ timeZone: "UTC",
+ });
+
+ return (
+
+
+
+ {baseTea} {withMilk ? "milk " : ""} tea
+
+ {addOns && addOns?.length > 0 && (
+
+ with {addOns?.join(", ").toLowerCase()}
+
+ )}
+ {instructions && (
+
{instructions}
+ )}
+
+ {date}
+
+ );
+}
diff --git a/examples/tanstack-form/src/Orders.tsx b/examples/tanstack-form/src/Orders.tsx
new file mode 100644
index 0000000000..ff6ad66e98
--- /dev/null
+++ b/examples/tanstack-form/src/Orders.tsx
@@ -0,0 +1,36 @@
+import { useAccount } from "jazz-tools/react";
+import { OrderThumbnail } from "./OrderThumbnail.tsx";
+import { JazzAccount } from "./schema.ts";
+
+export function Orders() {
+ const { me } = useAccount(JazzAccount, {
+ resolve: { root: { orders: true } },
+ });
+
+ return (
+ <>
+
+
+ Add new order
+
+
+
+
+ Your orders 🧋
+
+
+ {me?.root?.orders?.length ? (
+ me?.root?.orders.map((order) =>
+ order ?
: null,
+ )
+ ) : (
+
You have no orders yet.
+ )}
+
+
+ >
+ );
+}
diff --git a/examples/tanstack-form/src/apiKey.ts b/examples/tanstack-form/src/apiKey.ts
new file mode 100644
index 0000000000..ab9d18a535
--- /dev/null
+++ b/examples/tanstack-form/src/apiKey.ts
@@ -0,0 +1 @@
+export const apiKey = "tanstack-form-example@garden.co";
diff --git a/examples/tanstack-form/src/index.css b/examples/tanstack-form/src/index.css
new file mode 100644
index 0000000000..3ac55b60b0
--- /dev/null
+++ b/examples/tanstack-form/src/index.css
@@ -0,0 +1,26 @@
+@import "tailwindcss";
+@plugin "@tailwindcss/forms";
+
+@layer base {
+ :root {
+ --border-default: var(--color-stone-200);
+ }
+
+ .dark {
+ --border-default: var(--color-stone-900);
+ }
+
+ *,
+ ::after,
+ ::before,
+ ::backdrop,
+ ::file-selector-button {
+ border-color: var(--border-default, currentColor);
+ }
+}
+
+@layer components {
+ strong {
+ @apply font-semibold text-stone-900 dark:text-white;
+ }
+}
diff --git a/examples/tanstack-form/src/main.tsx b/examples/tanstack-form/src/main.tsx
new file mode 100644
index 0000000000..428f2b2ffb
--- /dev/null
+++ b/examples/tanstack-form/src/main.tsx
@@ -0,0 +1,22 @@
+import { JazzInspector } from "jazz-tools/inspector";
+import { JazzReactProvider } from "jazz-tools/react";
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+import App from "./App.tsx";
+import "./index.css";
+import { apiKey } from "./apiKey";
+import { JazzAccount } from "./schema.ts";
+
+createRoot(document.getElementById("root")!).render(
+
+
+
+
+
+ ,
+);
diff --git a/examples/tanstack-form/src/schema.ts b/examples/tanstack-form/src/schema.ts
new file mode 100644
index 0000000000..a798c0e1ff
--- /dev/null
+++ b/examples/tanstack-form/src/schema.ts
@@ -0,0 +1,44 @@
+import { co, z } from "jazz-tools";
+
+export const BubbleTeaAddOnTypes = [
+ "Pearl",
+ "Lychee jelly",
+ "Red bean",
+ "Brown sugar",
+ "Taro",
+] as const;
+
+export const BubbleTeaBaseTeaTypes = [
+ "Black",
+ "Oolong",
+ "Jasmine",
+ "Thai",
+] as const;
+
+export const ListOfBubbleTeaAddOns = co.list(z.enum(BubbleTeaAddOnTypes));
+
+export const BubbleTeaOrder = co.map({
+ baseTea: z.enum(BubbleTeaBaseTeaTypes),
+ addOns: ListOfBubbleTeaAddOns,
+ deliveryDate: z.date(),
+ withMilk: z.boolean(),
+ instructions: z.optional(co.plainText()),
+});
+
+/** The root is an app-specific per-user private `CoMap`
+ * where you can store top-level objects for that user */
+export const AccountRoot = co.map({
+ orders: co.list(BubbleTeaOrder),
+});
+
+export const JazzAccount = co
+ .account({
+ root: AccountRoot,
+ profile: co.profile(),
+ })
+ .withMigration((account) => {
+ if (!account.root) {
+ const orders = co.list(BubbleTeaOrder).create([], account);
+ account.root = AccountRoot.create({ orders }, account);
+ }
+ });
diff --git a/examples/tanstack-form/src/vite-env.d.ts b/examples/tanstack-form/src/vite-env.d.ts
new file mode 100644
index 0000000000..11f02fe2a0
--- /dev/null
+++ b/examples/tanstack-form/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/tanstack-form/tests/form.spec.ts b/examples/tanstack-form/tests/form.spec.ts
new file mode 100644
index 0000000000..7d75d3511a
--- /dev/null
+++ b/examples/tanstack-form/tests/form.spec.ts
@@ -0,0 +1,42 @@
+import { expect, test } from "@playwright/test";
+
+test("create and edit an order", async ({ page }) => {
+ await page.goto("/");
+ // start an order
+ await page.getByRole("link", { name: "Add new order" }).click();
+ await page.getByLabel("Base tea").selectOption("Oolong");
+
+ await page.getByLabel("Pearl").check();
+ await page.getByLabel("Taro").check();
+ await page.getByLabel("Delivery date").fill("2024-12-21");
+ await page.getByLabel("With milk?").check();
+ await page.getByLabel("Special instructions").fill("25% sugar");
+ await page.getByRole("button", { name: "Submit" }).click();
+
+ await page.waitForURL("/");
+
+ // check if order was created correctly
+ const firstOrder = page.getByRole("link", { name: "Oolong milk tea" });
+ await expect(firstOrder).toHaveText(/25% sugar/);
+ await expect(firstOrder).toHaveText(/12\/21\/2024/);
+ await expect(firstOrder).toHaveText(/with pearl, taro/);
+
+ // edit order
+ await firstOrder.click();
+ await page.getByLabel("Base tea").selectOption("Jasmine");
+ await page.getByLabel("Red bean").check();
+ await page.getByLabel("Brown sugar").check();
+ await page.getByLabel("Delivery date").fill("2024-12-25");
+ await page.getByLabel("With milk?").uncheck();
+ await page.getByLabel("Special instructions").fill("10% sugar");
+ await page.getByRole("button", { name: "Submit" }).click();
+ await page.getByRole("link", { name: /Back to all orders/ }).click();
+
+ // check if order was edited correctly
+ const editedOrder = page.getByRole("link", { name: "Jasmine tea" });
+ await expect(editedOrder).toHaveText(/10% sugar/);
+ await expect(editedOrder).toHaveText(/12\/25\/2024/);
+ await expect(editedOrder).toHaveText(
+ /with pearl, taro, red bean, brown sugar/,
+ );
+});
diff --git a/examples/tanstack-form/tsconfig.app.json b/examples/tanstack-form/tsconfig.app.json
new file mode 100644
index 0000000000..f03c8a6b22
--- /dev/null
+++ b/examples/tanstack-form/tsconfig.app.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ "moduleResolution": "Bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"]
+}
diff --git a/examples/tanstack-form/tsconfig.json b/examples/tanstack-form/tsconfig.json
new file mode 100644
index 0000000000..69751f1d67
--- /dev/null
+++ b/examples/tanstack-form/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/examples/tanstack-form/tsconfig.node.json b/examples/tanstack-form/tsconfig.node.json
new file mode 100644
index 0000000000..42872c59f5
--- /dev/null
+++ b/examples/tanstack-form/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/examples/tanstack-form/vercel.json b/examples/tanstack-form/vercel.json
new file mode 100644
index 0000000000..471d9a4166
--- /dev/null
+++ b/examples/tanstack-form/vercel.json
@@ -0,0 +1,3 @@
+{
+ "ignoreCommand": "npx turbo-ignore"
+}
diff --git a/examples/tanstack-form/vite.config.d.ts b/examples/tanstack-form/vite.config.d.ts
new file mode 100644
index 0000000000..340562aff1
--- /dev/null
+++ b/examples/tanstack-form/vite.config.d.ts
@@ -0,0 +1,2 @@
+declare const _default: import("vite").UserConfig;
+export default _default;
diff --git a/examples/tanstack-form/vite.config.ts b/examples/tanstack-form/vite.config.ts
new file mode 100644
index 0000000000..f16e2be3ff
--- /dev/null
+++ b/examples/tanstack-form/vite.config.ts
@@ -0,0 +1,7 @@
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+});
diff --git a/homepage/homepage/app/(others)/examples/page.tsx b/homepage/homepage/app/(others)/examples/page.tsx
index 79331c136c..2eac307db3 100644
--- a/homepage/homepage/app/(others)/examples/page.tsx
+++ b/homepage/homepage/app/(others)/examples/page.tsx
@@ -468,6 +468,15 @@ const reactExamples: Example[] = [
demoUrl: "https://form.demo.jazz.tools",
illustration: ,
},
+ {
+ name: "TanStack Form",
+ slug: "tanstack-form",
+ description:
+ "A form example for creating and editing CoValues using TanStack Form",
+ tech: [tech.react],
+ demoUrl: "https://tanstack-form.demo.jazz.tools",
+ illustration: ,
+ },
{
name: "Organization/Team",
slug: "organization",
diff --git a/packages/jazz-tools/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts b/packages/jazz-tools/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts
index 37e583e0cc..74ae1ec253 100644
--- a/packages/jazz-tools/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts
+++ b/packages/jazz-tools/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts
@@ -146,6 +146,8 @@ export type CoMapSchema<
): CoMapSchema;
getCoSchema: () => typeof CoMap;
+
+ getZodSchema: () => z.ZodObject;
};
export type optionalKeys = {
diff --git a/packages/jazz-tools/src/tools/implementation/zodSchema/zodCo.ts b/packages/jazz-tools/src/tools/implementation/zodSchema/zodCo.ts
index c2b1351398..8311ade8e5 100644
--- a/packages/jazz-tools/src/tools/implementation/zodSchema/zodCo.ts
+++ b/packages/jazz-tools/src/tools/implementation/zodSchema/zodCo.ts
@@ -64,6 +64,9 @@ function enrichCoMapSchema(
getCoSchema: () => {
return coSchema;
},
+ getZodSchema: () => {
+ return schema;
+ },
}) as unknown as CoMapSchema;
// Needs to be derived from the enriched schema
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 59642d9356..519d35ed9b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1423,6 +1423,64 @@ importers:
specifier: 6.3.5
version: 6.3.5(@types/node@22.15.18)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.19.3)(yaml@2.6.1)
+ examples/tanstack-form:
+ dependencies:
+ '@tanstack/react-form':
+ specifier: ^1.0.0
+ version: 1.12.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ hash-slash:
+ specifier: workspace:*
+ version: link:../../packages/hash-slash
+ jazz-tools:
+ specifier: workspace:*
+ version: link:../../packages/jazz-tools
+ react:
+ specifier: 19.0.0
+ version: 19.0.0
+ react-dom:
+ specifier: 19.0.0
+ version: 19.0.0(react@19.0.0)
+ devDependencies:
+ '@biomejs/biome':
+ specifier: 1.9.4
+ version: 1.9.4
+ '@playwright/test':
+ specifier: ^1.50.1
+ version: 1.50.1
+ '@tailwindcss/forms':
+ specifier: ^0.5.10
+ version: 0.5.10(tailwindcss@4.1.10)
+ '@tailwindcss/postcss':
+ specifier: ^4.1.10
+ version: 4.1.10
+ '@types/react':
+ specifier: 19.0.0
+ version: 19.0.0
+ '@types/react-dom':
+ specifier: 19.0.0
+ version: 19.0.0
+ '@vitejs/plugin-react':
+ specifier: ^4.5.1
+ version: 4.5.1(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.19.3)(yaml@2.6.1))
+ globals:
+ specifier: ^15.11.0
+ version: 15.15.0
+ is-ci:
+ specifier: ^3.0.1
+ version: 3.0.1
+ postcss:
+ specifier: ^8.4.40
+ version: 8.5.4
+ tailwindcss:
+ specifier: ^4.1.10
+ version: 4.1.10
+ typescript:
+ specifier: 5.6.2
+ version: 5.6.2
+ vite:
+ specifier: 6.3.5
+ version: 6.3.5(@types/node@22.15.18)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.19.3)(yaml@2.6.1)
+
examples/todo:
dependencies:
'@faker-js/faker':
@@ -5776,10 +5834,25 @@ packages:
peerDependencies:
vite: 6.3.5
+ '@tanstack/form-core@1.12.4':
+ resolution: {integrity: sha512-BhfNI5sEjI68Im1Vqezf9w68fJL4EB80cqW5w0zb/MV1erHHsXNRwLGmljF88VnCx1t/xd4fmF0D08wNajBauQ==}
+
'@tanstack/history@1.115.0':
resolution: {integrity: sha512-K7JJNrRVvyjAVnbXOH2XLRhFXDkeP54Kt2P4FR1Kl2KDGlIbkua5VqZQD2rot3qaDrpufyUa63nuLai1kOLTsQ==}
engines: {node: '>=12'}
+ '@tanstack/react-form@1.12.4':
+ resolution: {integrity: sha512-MsWHTTUl1Db7tcawbREEMjUtnjK1wC9HnwEITFFhO6e9jN4vR8gb7qRM6TDKg0tkBf42fd5jhEI5qCYA8Sl2pQ==}
+ peerDependencies:
+ '@tanstack/react-start': ^1.112.0
+ react: 19.0.0
+ vinxi: ^0.5.0
+ peerDependenciesMeta:
+ '@tanstack/react-start':
+ optional: true
+ vinxi:
+ optional: true
+
'@tanstack/react-router-devtools@1.116.0':
resolution: {integrity: sha512-PsJZWPjcmwZGe71kUvH4bI1ozkv1FgBuBEE0hTYlTCSJ3uG+qv3ndGEI+AiFyuF5OStrbfg0otW1OxeNq5vdGQ==}
engines: {node: '>=12'}
@@ -5801,6 +5874,12 @@ packages:
react: 19.0.0
react-dom: 19.0.0
+ '@tanstack/react-store@0.7.1':
+ resolution: {integrity: sha512-qUTEKdId6QPWGiWyKAPf/gkN29scEsz6EUSJ0C3HgLMgaqTAyBsQ2sMCfGVcqb+kkhEXAdjleCgH6LAPD6f2sA==}
+ peerDependencies:
+ react: 19.0.0
+ react-dom: 19.0.0
+
'@tanstack/router-core@1.115.3':
resolution: {integrity: sha512-gynHs72LHVg05fuJTwZZYhDL4VNEAK0sXz7IqiBv7a3qsYeEmIZsGaFr9sVjTkuF1kbrFBdJd5JYutzBh9Uuhw==}
engines: {node: '>=12'}
@@ -5854,6 +5933,9 @@ packages:
'@tanstack/store@0.7.0':
resolution: {integrity: sha512-CNIhdoUsmD2NolYuaIs8VfWM467RK6oIBAW4nPEKZhg1smZ+/CwtCdpURgp7nxSqOaV9oKkzdWD80+bC66F/Jg==}
+ '@tanstack/store@0.7.1':
+ resolution: {integrity: sha512-PjUQKXEXhLYj2X5/6c1Xn/0/qKY0IVFxTJweopRfF26xfjVyb14yALydJrHupDh3/d+1WKmfEgZPBVCmDkzzwg==}
+
'@tanstack/virtual-file-routes@1.115.0':
resolution: {integrity: sha512-XLUh1Py3AftcERrxkxC5Y5m5mfllRH3YR6YVlyjFgI2Tc2Ssy2NKmQFQIafoxfW459UJ8Dn81nWKETEIJifE4g==}
engines: {node: '>=12'}
@@ -7587,6 +7669,9 @@ packages:
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
+ decode-formdata@0.9.0:
+ resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==}
+
decode-uri-component@0.2.2:
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
engines: {node: '>=0.10'}
@@ -17819,8 +17904,22 @@ snapshots:
tailwindcss: 4.1.10
vite: 6.3.5(@types/node@22.15.18)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.19.3)(yaml@2.6.1)
+ '@tanstack/form-core@1.12.4':
+ dependencies:
+ '@tanstack/store': 0.7.1
+
'@tanstack/history@1.115.0': {}
+ '@tanstack/react-form@1.12.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@tanstack/form-core': 1.12.4
+ '@tanstack/react-store': 0.7.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ decode-formdata: 0.9.0
+ devalue: 5.1.1
+ react: 19.0.0
+ transitivePeerDependencies:
+ - react-dom
+
'@tanstack/react-router-devtools@1.116.0(@tanstack/react-router@1.116.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.115.3)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.116.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -17851,6 +17950,13 @@ snapshots:
react-dom: 19.0.0(react@19.0.0)
use-sync-external-store: 1.5.0(react@19.0.0)
+ '@tanstack/react-store@0.7.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@tanstack/store': 0.7.1
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ use-sync-external-store: 1.5.0(react@19.0.0)
+
'@tanstack/router-core@1.115.3':
dependencies:
'@tanstack/history': 1.115.0
@@ -17910,6 +18016,8 @@ snapshots:
'@tanstack/store@0.7.0': {}
+ '@tanstack/store@0.7.1': {}
+
'@tanstack/virtual-file-routes@1.115.0': {}
'@testing-library/dom@10.4.0':
@@ -20042,6 +20150,8 @@ snapshots:
decimal.js@10.4.3: {}
+ decode-formdata@0.9.0: {}
+
decode-uri-component@0.2.2: {}
decode-uri-component@0.4.1: {}