import {Forms, useForm, showToast} from "attio/client"// Form schema is constant (it cannot be changed via props)// so we should define it outside of the componentconst formSchema = { title: Forms.string(), url: Forms.string().url(), age: Forms.number().min(18), approved: Forms.boolean(), subscribed: Forms.boolean(),}export function SimpleFormDialog({ onDone } : { onDone: () => void }){ const { Form, TextInput, NumberInput, Checkbox, Toggle, SubmitButton, } = useForm(formSchema, { // These default values are required because these strings are required title: "", url: "", // No defaults are obligatory for required numbers or booleans // They default to 0 and false respectively }, ); return ( <Form onSubmit={async (values) => { // Usually you'd call a server function here await showToast({ title: "Form submitted", variant: "success", text: JSON.stringify(values, null, 2), }); onDone() }} > {/* These `name` props are strongly typed to your form schema */} <TextInput label="Title" name="title" /> <TextInput label="URL" name="url" /> <NumberInput label="Age" name="age" /> <Checkbox label="Approved" name="approved" /> <Toggle label="Subscribed" name="subscribed" /> {/* A `<SubmitButton/>` is required as a direct child of `<Form/>`. */} {/* No matter where you place it, it will be */} {/* rendered in the footer of the dialog. */} <SubmitButton label="Submit" /> </Form> );}
Sometimes you may need to add more complex validation than a static schema can express.
For example, you might want to ensure that the minimum value is less than the maximum value.
You can achieve this by passing a validation function to useForm().
complex-validation.tsx
Copy
Ask AI
import {Forms, useForm, showToast} from "attio/client"// Form schema is constant (it cannot be changed via props)// so we should define it outside of the componentconst formSchema = { min: Forms.number().min(0).max(100), max: Forms.number().min(0).max(100),}export function ComplexValidationDialog({ onDone } : { onDone: () => void }){ const { Form, NumberInput, SubmitButton, } = useForm(formSchema, {}, // As a third parameter to useForm(), you can pass a validation function // that takes all the form values and returns errors in the same shape // as the form values. (values) => { const errors = {} // empty errors object means validation passes if(values.min > values.max) { errors.min = "Must be less than max" errors.max = "Must be greater than than min" } return errors } ); return ( <Form onSubmit={async (values) => { // Usually you'd call a server function here await showToast({ title: "Form submitted", variant: "success", text: JSON.stringify(values, null, 2), }); onDone() }} > {/* These `name` props are strongly typed to your form schema */} <NumberInput label="Minimum" name="min" /> <NumberInput label="Maximum" name="max" /> {/* A `<SubmitButton/>` is required as a direct child of `<Form/>`. */} {/* No matter where you place it, it will be */} {/* rendered in the footer of the dialog. */} <SubmitButton label="Submit" /> </Form> );}