import { FormApi } from '@tanstack/form-core'
import { z } from 'zod'
interface FormData {
username: string
email: string
age: number
}
const form = new FormApi<FormData>({
// Initial values
defaultValues: {
username: '',
email: '',
age: 0,
},
// Form identification
formId: 'user-registration-form',
// Validation settings
asyncAlways: false,
asyncDebounceMs: 300,
canSubmitWhenInvalid: false,
// Validators
validators: {
onChange: ({ value }) => {
const errors: any = { fields: {} }
if (!value.username) {
errors.fields.username = 'Username is required'
}
if (!value.email) {
errors.fields.email = 'Email is required'
}
if (value.age < 18) {
errors.fields.age = 'Must be 18 or older'
}
return Object.keys(errors.fields).length > 0 ? errors : undefined
},
onChangeAsync: async ({ value }) => {
if (value.username) {
const available = await checkUsernameAvailability(value.username)
if (!available) {
return { fields: { username: 'Username already taken' } }
}
}
return undefined
},
onChangeAsyncDebounceMs: 500,
},
// Listeners
listeners: {
onChange: ({ formApi }) => {
console.log('Form changed:', formApi.state.values)
},
onMount: ({ formApi }) => {
console.log('Form mounted')
// Load saved draft if exists
const draft = localStorage.getItem('form-draft')
if (draft) {
formApi.reset(JSON.parse(draft), { keepDefaultValues: true })
}
},
},
// Submission handlers
onSubmit: async ({ value, formApi }) => {
console.log('Submitting:', value)
const response = await fetch('/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(value),
})
if (!response.ok) {
throw new Error('Registration failed')
}
console.log('Registration successful!')
localStorage.removeItem('form-draft')
},
onSubmitInvalid: ({ formApi }) => {
console.error('Form has errors:', formApi.state.errors)
alert('Please fix the errors before submitting')
},
})
async function checkUsernameAvailability(username: string): Promise<boolean> {
const response = await fetch(`/api/check-username?username=${username}`)
const data = await response.json()
return data.available
}