React Example: Simple

tsx
import * as React from 'react' import { createRoot } from 'react-dom/client' import { TanStackDevtools } from '@tanstack/react-devtools' import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' import { useForm } from '@tanstack/react-form' import type { AnyFieldApi } from '@tanstack/react-form' function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> {field.state.meta.isTouched && !field.state.meta.isValid ? ( <em>{field.state.meta.errors.join(',')}</em> ) : null} {field.state.meta.isValidating ? 'Validating...' : null} </> ) } export default function App() { const form = useForm({ defaultValues: { firstName: '', lastName: '', }, onSubmit: async ({ value }) => { // Do something with form data console.log(value) }, }) return ( <div> <h1>Simple Form Example</h1> <form onSubmit={(e) => { e.preventDefault() e.stopPropagation() form.handleSubmit() }} > <div> {/* A type-safe field component*/} <form.Field name="firstName" validators={{ onChange: ({ value }) => !value ? 'A first name is required' : value.length < 3 ? 'First name must be at least 3 characters' : undefined, onChangeAsyncDebounceMs: 500, onChangeAsync: async ({ value }) => { await new Promise((resolve) => setTimeout(resolve, 1000)) return ( value.includes('error') && 'No "error" allowed in first name' ) }, }} children={(field) => { // Avoid hasty abstractions. Render props are great! return ( <> <label htmlFor={field.name}>First Name:</label> <input id={field.name} name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} /> <FieldInfo field={field} /> </> ) }} /> </div> <div> <form.Field name="lastName" children={(field) => ( <> <label htmlFor={field.name}>Last Name:</label> <input id={field.name} name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} /> <FieldInfo field={field} /> </> )} /> </div> <form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]} children={([canSubmit, isSubmitting]) => ( <> <button type="submit" disabled={!canSubmit}> {isSubmitting ? '...' : 'Submit'} </button> <button type="reset" onClick={(e) => { // Avoid unexpected resets of form elements (especially <select> elements) e.preventDefault() form.reset() }} > Reset </button> </> )} /> </form> </div> ) } const rootElement = document.getElementById('root')! createRoot(rootElement).render( <React.StrictMode> <App /> <TanStackDevtools config={{ hideUntilHover: true }} plugins={[formDevtoolsPlugin()]} /> </React.StrictMode>, ) 
import * as React from 'react' import { createRoot } from 'react-dom/client' import { TanStackDevtools } from '@tanstack/react-devtools' import { formDevtoolsPlugin } from '@tanstack/react-form-devtools' import { useForm } from '@tanstack/react-form' import type { AnyFieldApi } from '@tanstack/react-form' function FieldInfo({ field }: { field: AnyFieldApi }) { return ( <> {field.state.meta.isTouched && !field.state.meta.isValid ? ( <em>{field.state.meta.errors.join(',')}</em> ) : null} {field.state.meta.isValidating ? 'Validating...' : null} </> ) } export default function App() { const form = useForm({ defaultValues: { firstName: '', lastName: '', }, onSubmit: async ({ value }) => { // Do something with form data console.log(value) }, }) return ( <div> <h1>Simple Form Example</h1> <form onSubmit={(e) => { e.preventDefault() e.stopPropagation() form.handleSubmit() }} > <div> {/* A type-safe field component*/} <form.Field name="firstName" validators={{ onChange: ({ value }) => !value ? 'A first name is required' : value.length < 3 ? 'First name must be at least 3 characters' : undefined, onChangeAsyncDebounceMs: 500, onChangeAsync: async ({ value }) => { await new Promise((resolve) => setTimeout(resolve, 1000)) return ( value.includes('error') && 'No "error" allowed in first name' ) }, }} children={(field) => { // Avoid hasty abstractions. Render props are great! return ( <> <label htmlFor={field.name}>First Name:</label> <input id={field.name} name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} /> <FieldInfo field={field} /> </> ) }} /> </div> <div> <form.Field name="lastName" children={(field) => ( <> <label htmlFor={field.name}>Last Name:</label> <input id={field.name} name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} /> <FieldInfo field={field} /> </> )} /> </div> <form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]} children={([canSubmit, isSubmitting]) => ( <> <button type="submit" disabled={!canSubmit}> {isSubmitting ? '...' : 'Submit'} </button> <button type="reset" onClick={(e) => { // Avoid unexpected resets of form elements (especially <select> elements) e.preventDefault() form.reset() }} > Reset </button> </> )} /> </form> </div> ) } const rootElement = document.getElementById('root')! createRoot(rootElement).render( <React.StrictMode> <App /> <TanStackDevtools config={{ hideUntilHover: true }} plugins={[formDevtoolsPlugin()]} /> </React.StrictMode>, )