import { TanStackDevtools } from '@tanstack/react-devtools'
import { useForm } from '@tanstack/react-form'
import { formDevtoolsPlugin } from '@tanstack/react-form-devtools'
import ReactDOM from 'react-dom/client'
import type { AnyFieldApi } from '@tanstack/react-form'
import './index.css'
interface FieldInfoProps {
field: AnyFieldApi
}
function FieldError({ field }: FieldInfoProps) {
return (
<small role={field.meta.isInvalid ? 'alert' : undefined} aria-live="polite">
{field.errors.map((e) => e.message).join('\n')}
</small>
)
}
function App() {
const form = useForm({
defaultValues: {
firstName: '',
lastName: '',
},
onSubmit: ({ value, createValidationError }) => {
console.log(value)
return createValidationError({
fields: {
firstName: 'Name already exists',
lastName: 'Name already exists',
},
})
},
})
return (
<div>
<h1>Simple Form Example</h1>
<form
onSubmit={(e) => {
e.preventDefault()
e.stopPropagation()
form.handleSubmit()
}}
>
{}
<form.Field
name="firstName"
validators={[
{
run: ({ value }) => {
if (value.length === 0) return 'A first name is required'
if (value.length < 3) return 'First name is too short'
},
triggers: ['change', 'blur'],
triggerDebounceMs: 300,
},
{
run: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return (
value.toLowerCase().includes('error') &&
'No "error" allowed in first name'
)
},
triggers: ['change'],
bailIfInvalid: true,
},
]}
>
{(field) => {
return (
<label className={field.meta.isValidating ? 'validating' : ''}>
<span>First Name</span>
<input
name={field.name}
value={field.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
aria-invalid={field.meta.isInvalid}
/>
<FieldError field={field} />
</label>
)
}}
</form.Field>
<form.Field name="lastName">
{(field) => (
<label className={field.meta.isValidating ? 'validating' : ''}>
<span>Last Name</span>
<input
name={field.name}
value={field.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
aria-invalid={field.meta.isInvalid}
/>
<FieldError field={field} />
</label>
)}
</form.Field>
{}
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
>
{([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit || isSubmitting}>
{isSubmitting ? '...' : 'Submit'}
</button>
)}
</form.Subscribe>
<button
type="reset"
onClick={(e) => {
e.preventDefault()
form.reset()
}}
>
Reset
</button>
</form>
<TanStackDevtools
plugins={[formDevtoolsPlugin()]}
config={{
hideUntilHover: false,
}}
/>
</div>
)
}
ReactDOM.createRoot(document.getElementById('root')!).render(<App />)