Skip to content

Commit e57b309

Browse files
authored
docs: add standard schema example to solid (#1670)
* docs: add standard schema example to solid * chore: fix Nx
1 parent 4a4de7f commit e57b309

File tree

10 files changed

+323
-0
lines changed

10 files changed

+323
-0
lines changed

docs/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,10 @@
601601
{
602602
"label": "Form Composition",
603603
"to": "framework/solid/examples/large-form"
604+
},
605+
{
606+
"label": "Standard Schema",
607+
"to": "framework/solid/examples/standard-schema"
604608
}
605609
]
606610
},
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Usage
2+
3+
```bash
4+
$ npm install # or pnpm install or yarn install
5+
```
6+
7+
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
8+
9+
## Available Scripts
10+
11+
In the project directory, you can run:
12+
13+
### `npm run dev`
14+
15+
Runs the app in the development mode.<br>
16+
Open [http://localhost:5173](http://localhost:5173) to view it in the browser.
17+
18+
### `npm run build`
19+
20+
Builds the app for production to the `dist` folder.<br>
21+
It correctly bundles Solid in production mode and optimizes the build for the best performance.
22+
23+
The build is minified and the filenames include the hashes.<br>
24+
Your app is ready to be deployed!
25+
26+
## Deployment
27+
28+
Learn more about deploying your application with the [documentations](https://vitejs.dev/guide/static-deploy.html)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>TanStack Form Solid Simple Example App</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/index.tsx"></script>
11+
</body>
12+
</html>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "@tanstack/form-example-solid-standard-schema",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "tsc && vite build",
8+
"test:types": "tsc",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"@tanstack/solid-form": "^1.15.3",
13+
"arktype": "^2.1.20",
14+
"effect": "^3.16.7",
15+
"react": "^19.0.0",
16+
"react-dom": "^19.0.0",
17+
"solid-js": "^1.9.7",
18+
"valibot": "^1.1.0",
19+
"zod": "^3.25.64"
20+
},
21+
"devDependencies": {
22+
"typescript": "5.8.2",
23+
"vite": "^6.3.5",
24+
"vite-plugin-solid": "^2.11.6"
25+
}
26+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/* @refresh reload */
2+
import { render } from 'solid-js/web'
3+
4+
import { createForm } from '@tanstack/solid-form'
5+
6+
import { type } from 'arktype'
7+
import * as v from 'valibot'
8+
import { z } from 'zod'
9+
import { Schema as S } from 'effect'
10+
import type { AnyFieldApi } from '@tanstack/solid-form'
11+
12+
const ZodSchema = z.object({
13+
firstName: z
14+
.string()
15+
.min(3, '[Zod] You must have a length of at least 3')
16+
.startsWith('A', "[Zod] First name must start with 'A'"),
17+
lastName: z.string().min(3, '[Zod] You must have a length of at least 3'),
18+
})
19+
20+
const ValibotSchema = v.object({
21+
firstName: v.pipe(
22+
v.string(),
23+
v.minLength(3, '[Valibot] You must have a length of at least 3'),
24+
v.startsWith('A', "[Valibot] First name must start with 'A'"),
25+
),
26+
lastName: v.pipe(
27+
v.string(),
28+
v.minLength(3, '[Valibot] You must have a length of at least 3'),
29+
),
30+
})
31+
32+
const ArkTypeSchema = type({
33+
firstName: 'string >= 3',
34+
lastName: 'string >= 3',
35+
})
36+
37+
const EffectSchema = S.standardSchemaV1(
38+
S.Struct({
39+
firstName: S.String.pipe(
40+
S.minLength(3),
41+
S.annotations({
42+
message: () => '[Effect/Schema] You must have a length of at least 3',
43+
}),
44+
),
45+
lastName: S.String.pipe(
46+
S.minLength(3),
47+
S.annotations({
48+
message: () => '[Effect/Schema] You must have a length of at least 3',
49+
}),
50+
),
51+
}),
52+
)
53+
54+
interface FieldInfoProps {
55+
field: AnyFieldApi
56+
}
57+
58+
function FieldInfo(props: FieldInfoProps) {
59+
return (
60+
<>
61+
{props.field.state.meta.isTouched && !props.field.state.meta.isValid ? (
62+
<em>
63+
{props.field.state.meta.errors.map((err) => err.message).join(',')}
64+
</em>
65+
) : null}
66+
{props.field.state.meta.isValidating ? 'Validating...' : null}
67+
</>
68+
)
69+
}
70+
71+
function App() {
72+
const form = createForm(() => ({
73+
defaultValues: {
74+
firstName: '',
75+
lastName: '',
76+
},
77+
validators: {
78+
// DEMO: You can switch between schemas seamlessly
79+
onChange: ZodSchema,
80+
// onChange: ValibotSchema,
81+
// onChange: ArkTypeSchema,
82+
// onChange: EffectSchema,
83+
},
84+
onSubmit: async ({ value }) => {
85+
// Do something with form data
86+
console.log(value)
87+
},
88+
}))
89+
90+
return (
91+
<div>
92+
<h1>Simple Form Example</h1>
93+
<form
94+
onSubmit={(e) => {
95+
e.preventDefault()
96+
e.stopPropagation()
97+
form.handleSubmit()
98+
}}
99+
>
100+
<div>
101+
{/* A type-safe field component*/}
102+
<form.Field
103+
name="firstName"
104+
children={(field) => {
105+
// Avoid hasty abstractions. Render props are great!
106+
return (
107+
<>
108+
<label for={field().name}>First Name:</label>
109+
<input
110+
id={field().name}
111+
name={field().name}
112+
value={field().state.value}
113+
onBlur={field().handleBlur}
114+
onInput={(e) => field().handleChange(e.target.value)}
115+
/>
116+
<FieldInfo field={field()} />
117+
</>
118+
)
119+
}}
120+
/>
121+
</div>
122+
<div>
123+
<form.Field
124+
name="lastName"
125+
children={(field) => (
126+
<>
127+
<label for={field().name}>Last Name:</label>
128+
<input
129+
id={field().name}
130+
name={field().name}
131+
value={field().state.value}
132+
onBlur={field().handleBlur}
133+
onInput={(e) => field().handleChange(e.target.value)}
134+
/>
135+
<FieldInfo field={field()} />
136+
</>
137+
)}
138+
/>
139+
</div>
140+
<form.Subscribe
141+
selector={(state) => ({
142+
canSubmit: state.canSubmit,
143+
isSubmitting: state.isSubmitting,
144+
})}
145+
children={(state) => {
146+
return (
147+
<button type="submit" disabled={!state().canSubmit}>
148+
{state().isSubmitting ? '...' : 'Submit'}
149+
</button>
150+
)
151+
}}
152+
/>
153+
</form>
154+
</div>
155+
)
156+
}
157+
158+
const root = document.getElementById('root')
159+
160+
render(() => <App />, root!)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"useDefineForClassFields": true,
5+
"module": "ESNext",
6+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
7+
"skipLibCheck": true,
8+
9+
/* Bundler mode */
10+
"moduleResolution": "Bundler",
11+
"allowImportingTsExtensions": true,
12+
"resolveJsonModule": true,
13+
"isolatedModules": true,
14+
"noEmit": true,
15+
"jsx": "preserve",
16+
"jsxImportSource": "solid-js",
17+
18+
/* Linting */
19+
"strict": true,
20+
"noUnusedLocals": false,
21+
"noUnusedParameters": true,
22+
"noFallthroughCasesInSwitch": true
23+
},
24+
"include": ["src", "vite.config.ts"]
25+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { defineConfig } from 'vite'
2+
import solid from 'vite-plugin-solid'
3+
4+
export default defineConfig({
5+
plugins: [solid()],
6+
})

pnpm-lock.yaml

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)