Skip to content

Commit 5808c88

Browse files
authored
docs: add Svelte standard schema example (#1671)
docs: add standard schema example
1 parent e57b309 commit 5808c88

File tree

13 files changed

+308
-0
lines changed

13 files changed

+308
-0
lines changed

docs/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@
639639
{
640640
"label": "Arrays",
641641
"to": "framework/svelte/examples/array"
642+
},
643+
{
644+
"label": "Standard Schema",
645+
"to": "framework/svelte/examples/standard-schema"
642646
}
643647
]
644648
}
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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Example
2+
3+
To run this example:
4+
5+
- `npm install`
6+
- `npm run dev`
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + Svelte + TS</title>
8+
</head>
9+
<body>
10+
<div id="app"></div>
11+
<script type="module" src="/src/main.ts"></script>
12+
</body>
13+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@tanstack/form-example-svelte-standard-schema",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"@tanstack/svelte-form": "^1.15.1",
13+
"arktype": "^2.1.20",
14+
"effect": "^3.16.7",
15+
"valibot": "^1.1.0",
16+
"zod": "^3.25.64"
17+
},
18+
"devDependencies": {
19+
"@sveltejs/vite-plugin-svelte": "^5.1.0",
20+
"@tsconfig/svelte": "^5.0.4",
21+
"svelte": "^5.34.3",
22+
"typescript": "5.8.2",
23+
"vite": "^6.3.5"
24+
}
25+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<script lang="ts">
2+
import { createForm } from '@tanstack/svelte-form'
3+
import FieldInfo from './FieldInfo.svelte'
4+
5+
import { type } from 'arktype'
6+
import * as v from 'valibot'
7+
import { z } from 'zod'
8+
import { Schema as S } from 'effect'
9+
10+
const ZodSchema = z.object({
11+
firstName: z
12+
.string()
13+
.min(3, '[Zod] You must have a length of at least 3')
14+
.startsWith('A', "[Zod] First name must start with 'A'"),
15+
lastName: z.string().min(3, '[Zod] You must have a length of at least 3'),
16+
})
17+
18+
const ValibotSchema = v.object({
19+
firstName: v.pipe(
20+
v.string(),
21+
v.minLength(3, '[Valibot] You must have a length of at least 3'),
22+
v.startsWith('A', "[Valibot] First name must start with 'A'"),
23+
),
24+
lastName: v.pipe(
25+
v.string(),
26+
v.minLength(3, '[Valibot] You must have a length of at least 3'),
27+
),
28+
})
29+
30+
const ArkTypeSchema = type({
31+
firstName: 'string >= 3',
32+
lastName: 'string >= 3',
33+
})
34+
35+
const EffectSchema = S.standardSchemaV1(
36+
S.Struct({
37+
firstName: S.String.pipe(
38+
S.minLength(3),
39+
S.annotations({
40+
message: () => '[Effect/Schema] You must have a length of at least 3',
41+
}),
42+
),
43+
lastName: S.String.pipe(
44+
S.minLength(3),
45+
S.annotations({
46+
message: () => '[Effect/Schema] You must have a length of at least 3',
47+
}),
48+
),
49+
}),
50+
)
51+
52+
const form = createForm(() => ({
53+
defaultValues: {
54+
firstName: '',
55+
lastName: '',
56+
},
57+
validators: {
58+
// DEMO: You can switch between schemas seamlessly
59+
onChange: ZodSchema,
60+
// onChange: ValibotSchema,
61+
// onChange: ArkTypeSchema,
62+
// onChange: EffectSchema,
63+
},
64+
onSubmit: async ({ value }) => {
65+
// Do something with form data
66+
alert(JSON.stringify(value))
67+
},
68+
}))
69+
</script>
70+
71+
<form
72+
id="form"
73+
onsubmit={(e) => {
74+
e.preventDefault()
75+
e.stopPropagation()
76+
form.handleSubmit()
77+
}}
78+
>
79+
<h1>TanStack Form - Svelte Demo</h1>
80+
81+
<form.Field
82+
name="firstName"
83+
>
84+
{#snippet children(field)}
85+
<div>
86+
<label for={field.name}>First Name</label>
87+
<input
88+
id={field.name}
89+
type="text"
90+
placeholder="First Name"
91+
value={field.state.value}
92+
onblur={() => field.handleBlur()}
93+
oninput={(e: Event) => {
94+
const target = e.target as HTMLInputElement
95+
field.handleChange(target.value)
96+
}}
97+
/>
98+
<FieldInfo {field} />
99+
</div>
100+
{/snippet}
101+
</form.Field>
102+
<form.Field
103+
name="lastName"
104+
>
105+
{#snippet children(field)}
106+
<div>
107+
<label for={field.name}>Last Name</label>
108+
<input
109+
id={field.name}
110+
type="text"
111+
placeholder="Last Name"
112+
value={field.state.value}
113+
onblur={() => field.handleBlur()}
114+
oninput={(e: Event) => {
115+
const target = e.target as HTMLInputElement
116+
field.handleChange(target.value)
117+
}}
118+
/>
119+
<FieldInfo {field} />
120+
</div>
121+
{/snippet}
122+
</form.Field>
123+
<div>
124+
<form.Subscribe
125+
selector={(state) => ({
126+
canSubmit: state.canSubmit,
127+
isSubmitting: state.isSubmitting,
128+
})}
129+
>
130+
{#snippet children({ canSubmit, isSubmitting })}
131+
<button type="submit" disabled={!canSubmit}>
132+
{isSubmitting ? 'Submitting' : 'Submit'}
133+
</button>
134+
{/snippet}
135+
</form.Subscribe>
136+
<button
137+
type="button"
138+
id="reset"
139+
onclick={() => {
140+
form.reset()
141+
}}
142+
>
143+
Reset
144+
</button>
145+
</div>
146+
</form>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script lang="ts">
2+
import type { AnyFieldApi } from '@tanstack/svelte-form'
3+
4+
let { field }: { field: AnyFieldApi } = $props()
5+
</script>
6+
7+
{#if field.state.meta.isTouched}
8+
{#each field.state.meta.errors as error}
9+
<em>{error.message}</em>
10+
{/each}
11+
{field.state.meta.isValidating ? 'Validating...' : ''}
12+
{/if}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { mount } from 'svelte'
2+
import App from './App.svelte'
3+
4+
const app = mount(App, {
5+
target: document.getElementById('app')!,
6+
})
7+
8+
export default app
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/// <reference types="svelte" />
2+
/// <reference types="vite/client" />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
2+
3+
export default {
4+
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
5+
// for more information about preprocessors
6+
preprocess: vitePreprocess(),
7+
}

0 commit comments

Comments
 (0)