### Install Formisch Package Source: https://formisch.dev/react/guides/installation.md Add the Formisch library to your project. ```bash npm install @formisch/react # npm yarn add @formisch/react # yarn pnpm add @formisch/react # pnpm bun add @formisch/react # bun deno add npm:@formisch/react # deno ``` -------------------------------- ### Install AI Agent Skills Source: https://formisch.dev/react/guides/installation.md Install agent skills to assist AI agents with Valibot and Formisch patterns. ```bash npx skills add open-circle/agent-skills ``` -------------------------------- ### Install Valibot Dependency Source: https://formisch.dev/react/guides/installation.md Install Valibot as a peer dependency using your preferred package manager. ```bash npm install valibot # npm yarn add valibot # yarn pnpm add valibot # pnpm bun add valibot # bun deno add npm:valibot # deno ``` -------------------------------- ### Standard Field Implementation Source: https://formisch.dev/react/guides/input-components.md Example of a raw Field component implementation before encapsulation. ```tsx {(field) => (
{field.errors &&
{field.errors[0]}
}
)}
``` -------------------------------- ### Formisch Method Usage Examples Source: https://formisch.dev/react/guides/form-methods.md Demonstrates common operations including reading field values, resetting form state, and manipulating array fields. ```tsx // Get the value of a field const emailInput = getInput(loginForm, { path: ['email'] }); // Reset the form with new initial values reset(loginForm, { initialInput: { email: '', password: '' } }); // Move an item in a field array move(loginForm, { path: ['items'], from: 0, to: 3 }); ``` -------------------------------- ### Encapsulated TextInput Implementation Source: https://formisch.dev/react/guides/input-components.md Example of using a custom TextInput component to simplify form field markup. ```tsx {(field) => ( )} ``` -------------------------------- ### Define Valibot Schema with Transformations Source: https://formisch.dev/react/guides/dirty-fields.md Example of a schema that transforms input strings into trimmed strings and numbers. ```tsx import * as v from 'valibot'; const Schema = v.object({ name: v.pipe(v.string(), v.trim()), age: v.pipe(v.string(), v.toNumber()), }); ``` -------------------------------- ### Initialize a form with useForm and Field Source: https://formisch.dev/react/guides/introduction.md Demonstrates setting up a login form with validation using Valibot and connecting inputs via the Field component. ```tsx import { Field, Form, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function LoginPage() { const loginForm = useForm({ schema: LoginSchema, }); return (
console.log(output)}> {(field) => (
{field.errors &&
{field.errors[0]}
}
)}
{(field) => (
{field.errors &&
{field.errors[0]}
}
)}
); } ``` -------------------------------- ### Initialize a form with useForm Source: https://formisch.dev/react/guides/create-your-form.md Use the useForm hook to create a form store linked to a Valibot schema. ```tsx import { Field, Form, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function App() { const loginForm = useForm({ schema: LoginSchema, }); return
{/* Form fields will go here */}
; } ``` -------------------------------- ### Initialize useForm Source: https://formisch.dev/react/api/useForm.md Creates a reactive form store by passing a configuration object with a generic schema type. ```ts const form = useForm(config); ``` -------------------------------- ### Visualize the Formisch package hierarchy Source: https://formisch.dev/react/guides/architecture.md A structural representation showing the dependency flow from the React layer down to the framework adapter. ```text @formisch/react ├─ useForm,
, , … (React-specific reactive layer) └─ re-exports @formisch/methods/react (focus, reset, validate, …) └─ @formisch/core/react (createFormStore, types, signals) └─ framework adapter (createSignal, batch, untrack, createId) ``` -------------------------------- ### useForm(config) Source: https://formisch.dev/react/api/useForm.md Creates a reactive form store from a form configuration. ```APIDOC ## useForm(config) ### Description Creates a reactive form store that manages form state using the provided Valibot schema. Validation runs when the form is submitted by default, with customizable validation and revalidation options. ### Parameters - **config** (object) - Required - The form configuration object. ### Returns - **form** (FormStore) - A reactive form store object. ``` -------------------------------- ### Initialize useField Source: https://formisch.dev/react/api/useField.md Creates a reactive field store by providing the form instance and configuration. ```ts const field = useField(form, config); ``` -------------------------------- ### Configure useForm options Source: https://formisch.dev/react/guides/create-your-form.md Customize form behavior by providing initial input values and validation timing settings. ```tsx const loginForm = useForm({ schema: LoginSchema, initialInput: { email: 'user@example.com', }, validate: 'initial', revalidate: 'input', }); ``` -------------------------------- ### Handling input and output types with transformations Source: https://formisch.dev/react/guides/typescript.md Shows how Formisch handles schemas with transformations, correctly typing both the raw input and the transformed output. ```tsx import { Field, Form, useForm } from '@formisch/react'; import * as v from 'valibot'; const ProfileSchema = v.object({ age: v.pipe( v.string(), // Input type: string (from HTML input) v.transform((input) => Number(input)), // Output type: number v.number() ), birthDate: v.pipe( v.string(), // Input type: string (ISO date string) v.transform((input) => new Date(input)), // Output type: Date v.date() ), }); export default function ProfilePage() { const profileForm = useForm({ schema: ProfileSchema, }); return ( { // output is: { age: number; birthDate: Date } console.log(output.age); // number console.log(output.birthDate); // Date }} > {(field) => ( // field.input is string )} {(field) => ( // field.input is string )} ); } ``` -------------------------------- ### Implement React Signal Adapter Source: https://formisch.dev/react/guides/architecture.md A custom pub/sub implementation used by the React adapter to provide signal-like behavior where native primitives are missing. ```ts export function createSignal(value: T): Signal { const subscribers = new Set(); return { get value() { if (listener) { subscribers.add(listener); listener[1].add(subscribers); } return value; }, set value(newValue: T) { if (newValue !== value) { value = newValue; // notify subscribers … } }, }; } ``` -------------------------------- ### Implement file inputs Source: https://formisch.dev/react/guides/special-inputs.md Handle single or multiple file uploads using the file input type. ```tsx {(field) => } ``` ```tsx {(field) => } ``` -------------------------------- ### Implement TextInput component function Source: https://formisch.dev/react/guides/input-components.md Sets up the component function structure with prop destructuring. ```tsx import type { FieldElementProps } from '@formisch/react'; interface TextInputProps extends FieldElementProps { /* ... */ } export function TextInput({ label, input, errors, ...props }: TextInputProps) { // Component implementation } ``` -------------------------------- ### Define a schema with optional fields Source: https://formisch.dev/react/guides/define-your-form.md Demonstrates how to use v.optional to handle fields that are not required during form submission. ```ts import * as v from 'valibot'; const ProfileSchema = v.object({ name: v.pipe(v.string(), v.nonEmpty()), bio: v.optional(v.string()), // <- Optional field }); ``` -------------------------------- ### Create the internal form store Source: https://formisch.dev/react/guides/architecture.md The internal store is created within a useMemo hook, capturing the schema for validation. ```ts const internalFormStore = useMemo( () => createFormStore(config, (input) => v.safeParseAsync(config.schema, input)), [] ); ``` -------------------------------- ### Define field paths Source: https://formisch.dev/react/guides/add-form-fields.md Demonstrates how to target top-level and nested fields within a schema using the path property. ```tsx {(field) => } ``` ```tsx // For a schema like: v.object({ user: v.object({ email: v.string() }) }) {(field) => } ``` -------------------------------- ### Inferring form types from Valibot schemas Source: https://formisch.dev/react/guides/typescript.md Demonstrates how useForm automatically derives the form structure from a provided Valibot schema. ```tsx import { Field, Form, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function LoginPage() { const loginForm = useForm({ schema: LoginSchema, }); // TypeScript knows the form structure from the schema // loginForm is of type FormStore return (
{ // output is fully typed based on LoginSchema console.log(output.email); // ✓ Type-safe console.log(output.username); // ✗ TypeScript error }} > {/* Form fields */}
); } ``` -------------------------------- ### Reference array items by index in path Source: https://formisch.dev/react/guides/field-arrays.md Demonstrates how to use the index from the map function within the path array to target specific array items. ```tsx {(field) => } ``` -------------------------------- ### Import Formisch Source: https://formisch.dev/react/guides/installation.md Import Formisch components or utilities into your project files. ```typescript import { … } from '@formisch/react'; ``` -------------------------------- ### Implement select elements Source: https://formisch.dev/react/guides/special-inputs.md Handle single and multiple selection dropdowns using the select element. ```tsx {(field) => ( )} ``` ```tsx {(field) => ( {/* Set "multiple" to "true" */} )} ``` -------------------------------- ###
Source: https://formisch.dev/react/api/Form.md The Form component manages form submission and state. It wraps a native HTML form element and accepts a form store reference and an onSubmit handler. ```APIDOC ## ### Description A component that wraps a native HTML `` element to manage submission events and internal state. It disables default browser validation and triggers the provided `onSubmit` handler upon successful validation. ### Properties - **of** (any) - Required - Reference to the form store. - **children** (ReactNode) - Required - The content to be rendered inside the form. - **onSubmit** (function) - Required - Callback function executed when the form is submitted. ### Usage Example ```tsx ``` ``` -------------------------------- ### useField(form, config) Source: https://formisch.dev/react/api/useField.md Creates a reactive field store for a specific field path within a form store. ```APIDOC ## useField(form, config) ### Description Creates a reactive field store of a specific field within a form store. It provides reactive access to the field's input value, validation errors, touched state, and includes a `props` object for automatic handling of HTML input interactions. ### Parameters - **form** (Object) - Required - The form store instance. - **config** (Object) - Required - Configuration object for the field. ### Generics - **TSchema** - The schema type of the form. - **TFieldPath** - The path type of the field within the schema. ### Returns - **field** (FieldStore) - A reactive field store object. ``` -------------------------------- ### Basic Form Usage Source: https://formisch.dev/react/api/Form.md The Form component requires an 'of' prop to reference the form store and an 'onSubmit' handler. ```tsx
children
``` -------------------------------- ### Manage multiple forms on one page Source: https://formisch.dev/react/guides/create-your-form.md Create independent form stores by calling useForm multiple times within the same component. ```tsx import { Form, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); const RegisterSchema = v.object({ username: v.pipe(v.string(), v.minLength(3)), email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function App() { const loginForm = useForm({ schema: LoginSchema }); const registerForm = useForm({ schema: RegisterSchema }); return ( <>
{/* … */}
{/* … */}
); } ``` -------------------------------- ### Basic FieldArray Usage Source: https://formisch.dev/react/api/FieldArray.md The fundamental syntax for implementing a FieldArray component with required store and path props. ```tsx children ``` -------------------------------- ### Create Generic Field Components Source: https://formisch.dev/react/guides/typescript.md Define reusable field components by typing the 'of' prop with FormStore and a GenericSchema. ```tsx import { type FormStore, useField } from '@formisch/react'; import type { FunctionComponent } from 'react'; import * as v from 'valibot'; type EmailInputProps = { of: FormStore>; }; const EmailInput: FunctionComponent = (props) => { const field = useField(props.of, { path: ['email'] }); return (
{field.errors &&
{field.errors[0]}
}
); }; ``` -------------------------------- ### UseFieldArrayConfig Source: https://formisch.dev/react/api/UseFieldArrayConfig.md The configuration object structure for useFieldArray, including generics for schema and path definition. ```APIDOC ## UseFieldArrayConfig ### Description Configuration object used to define the field array store when calling `useFieldArray`. ### Generics - **TSchema**: The schema type for the form. - **TFieldArrayPath**: The path type for the field array. ### Definition - **path**: The path to the field array within the form schema. ``` -------------------------------- ### Define a login schema with Valibot Source: https://formisch.dev/react/guides/define-your-form.md Defines a schema with required email and password fields, including custom validation error messages. ```ts import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe( v.string(), v.nonEmpty('Please enter your email.'), v.email('The email address is badly formatted.') ), password: v.pipe( v.string(), v.nonEmpty('Please enter your password.'), v.minLength(8, 'Your password must have 8 characters or more.') ), }); ``` -------------------------------- ### Expose the public form store Source: https://formisch.dev/react/guides/architecture.md The React wrapper memoizes the public form store, exposing internal signals through getters. ```ts return useMemo( () => ({ [INTERNAL]: internalFormStore, get isSubmitting() { return internalFormStore.isSubmitting.value; }, get isTouched() { return getFieldBool(internalFormStore, 'isTouched'); }, // … }), [internalFormStore] ); ``` -------------------------------- ### Implement a form with Field components Source: https://formisch.dev/react/guides/add-form-fields.md Uses the Field component to connect form inputs to a Valibot schema, providing field state and props for rendering. ```tsx import { Field, Form, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function App() { const loginForm = useForm({ schema: LoginSchema, }); return (
{(field) => } {(field) => ( )}
); } ``` -------------------------------- ### Implement an array of checkboxes Source: https://formisch.dev/react/guides/special-inputs.md Use multiple checkboxes to manage an array of strings by providing a value attribute. ```tsx { [ { label: 'Bananas', value: 'bananas' }, { label: 'Apples', value: 'apples' }, { label: 'Grapes', value: 'grapes' }, ].map(({ label, value }) => ( {(field) => ( )} )); } ``` -------------------------------- ### Validating field paths with TypeScript Source: https://formisch.dev/react/guides/typescript.md Illustrates how TypeScript provides autocompletion and compile-time errors for Field component paths based on the schema structure. ```tsx const UserSchema = v.object({ profile: v.object({ name: v.object({ first: v.string(), last: v.string(), }), email: v.string(), }), }); const userForm = useForm({ schema: UserSchema }); // ✓ Valid paths - TypeScript provides autocompletion // ✗ Invalid paths - TypeScript error ``` -------------------------------- ### Define a field array schema with Valibot Source: https://formisch.dev/react/guides/field-arrays.md Defines a schema for a todo list using Valibot, enforcing constraints like non-empty strings and array length limits. ```tsx import * as v from 'valibot'; const TodoFormSchema = v.object({ heading: v.pipe(v.string(), v.nonEmpty()), todos: v.pipe( v.array( v.object({ label: v.pipe(v.string(), v.nonEmpty()), deadline: v.pipe(v.string(), v.nonEmpty()), }) ), v.nonEmpty(), v.maxLength(10) ), }); ``` -------------------------------- ### Insert item into field array Source: https://formisch.dev/react/guides/field-arrays.md Adds a new item to the specified array path. Use the 'at' option to define the insertion index, otherwise it defaults to the end. ```tsx import { insert } from '@formisch/react'; ; ``` -------------------------------- ### Display loading state during submission Source: https://formisch.dev/react/guides/handle-submission.md Use the isSubmitting property from the form store to provide visual feedback and disable buttons while the form is processing. ```tsx ``` -------------------------------- ### Create a controlled date input component Source: https://formisch.dev/react/guides/controlled-fields.md Handles conversion between Date objects and YYYY-MM-DD strings required by HTML date inputs. ```tsx import type { FieldElementProps } from '@formisch/react'; import { useMemo } from 'react'; interface DateInputProps extends Omit { label?: string; placeholder?: string; input: Date | undefined; errors: [string, ...string[]] | null; required?: boolean; onChange: (value: Date | undefined) => void; } export function DateInput({ label, input, errors, name, onChange, ...inputProps }: DateInputProps) { // Transform date to string const value = useMemo( () => input && !Number.isNaN(input.getTime()) ? input.toISOString().split('T', 1)[0] : '', [input] ); return (
{label && } onChange(event.currentTarget.valueAsDate ?? undefined) } aria-invalid={!!errors} aria-errormessage={`${name}-error`} /> {errors &&
{errors[0]}
}
); } ``` -------------------------------- ### Configure TypeScript Strict Mode Source: https://formisch.dev/react/guides/installation.md Enable strict mode in tsconfig.json to ensure correct type calculation. ```json { "compilerOptions": { "strict": true, // ... } } ``` -------------------------------- ### Use the FieldError component in a form field Source: https://formisch.dev/react/guides/validation.md Demonstrates how to integrate the reusable FieldError component within a Field render prop. ```tsx {(field) => (
)}
``` -------------------------------- ### Basic Field Usage Source: https://formisch.dev/react/api/Field.md The Field component requires an 'of' prop for the form store and a 'path' prop to identify the specific field. ```tsx children ``` -------------------------------- ### Implement number input in a form Source: https://formisch.dev/react/guides/controlled-fields.md Passes the custom onChange handler to override the native input behavior. ```tsx {(field) => ( )} ``` -------------------------------- ### Initialize useFieldArray Source: https://formisch.dev/react/api/useFieldArray.md Creates a reactive field array store for a specific array field within a form. ```ts const fieldArray = useFieldArray(form, config); ``` -------------------------------- ### Complete TextInput component code Source: https://formisch.dev/react/guides/input-components.md The full implementation of the TextInput component in a single block. ```tsx import type { FieldElementProps } from '@formisch/react'; interface TextInputProps extends FieldElementProps { type: 'text' | 'email' | 'tel' | 'password' | 'url' | 'date'; label?: string; placeholder?: string; input: string | undefined; errors: [string, ...string[]] | null; required?: boolean; } export function TextInput({ label, input, errors, ...props }: TextInputProps) { const { name, required } = props; return (
{label && ( )} {errors &&
{errors[0]}
}
); } ``` -------------------------------- ### Define the Signal interface Source: https://formisch.dev/react/guides/architecture.md The core interface for all reactive state in Formisch, providing a minimal getter and setter. ```ts interface Signal { get value(): T; set value(nextValue: T): void; } ``` -------------------------------- ### Implement a radio button group Source: https://formisch.dev/react/guides/special-inputs.md Use a group of radio buttons to allow selecting a single option from a list. ```tsx {(field) => ( <> {[ { label: 'Red', value: 'red' }, { label: 'Green', value: 'green' }, { label: 'Blue', value: 'blue' }, ].map(({ label, value }) => ( ))} )} ``` -------------------------------- ### Implement date input in a form Source: https://formisch.dev/react/guides/controlled-fields.md Overrides the native change handler to ensure Date objects are stored correctly. ```tsx {(field) => ( )} ``` -------------------------------- ### Handle submission without a form element Source: https://formisch.dev/react/guides/handle-submission.md Use the handleSubmit method to process form data when a standard
wrapper is not feasible. ```tsx import { Field, handleSubmit, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function App() { const loginForm = useForm({ schema: LoginSchema, }); const submitForm = handleSubmit(loginForm, (values) => { // Process the validated form values console.log(values); }); return (
{/* Form fields without a wrapper */}
); } ``` -------------------------------- ### Validate field array length with Valibot Source: https://formisch.dev/react/guides/field-arrays.md Use v.pipe with v.array and length constraints to enforce array size limits in a schema. ```tsx const TodoFormSchema = v.object({ todos: v.pipe( v.array( v.object({ label: v.string(), deadline: v.string(), }) ), v.minLength(1), v.maxLength(10) ), }); ``` -------------------------------- ### useFieldArray(form, config) Source: https://formisch.dev/react/api/useFieldArray.md Creates a reactive field array store for a specific array field within a form store, enabling management of dynamic field lists. ```APIDOC ## useFieldArray(form, config) ### Description Creates a reactive field array store for a specific array field within a form store. This hook provides reactive access to array items, validation errors, and touched state, facilitating the management of dynamic arrays. ### Parameters - **form** (object) - Required - The form store instance. - **config** (object) - Required - Configuration object for the field array. ### Generics - **TSchema** - The schema type of the form. - **TFieldArrayPath** - The path type of the field array within the schema. ### Returns - **fieldArray** (FieldArrayStore) - A reactive store for the specified field array. ``` -------------------------------- ### Create a controlled number input component Source: https://formisch.dev/react/guides/controlled-fields.md Encapsulates logic to convert input strings to numbers and handle NaN states during typing. ```tsx import type { FieldElementProps } from '@formisch/react'; import { useMemo, useRef } from 'react'; interface NumberInputProps extends Omit { label?: string; placeholder?: string; input: number | undefined; errors: [string, ...string[]] | null; required?: boolean; onChange: (value: number | undefined) => void; } export function NumberInput({ label, input, errors, name, onChange, ...inputProps }: NumberInputProps) { const prevValue = useRef(); // Get value, keeping previous value if NaN const value = useMemo(() => { if (typeof input === 'number' && !Number.isNaN(input)) { prevValue.current = input; return input; } return prevValue.current; }, [input]); return (
{label && } onChange( event.currentTarget.value === '' ? undefined : event.currentTarget.valueAsNumber ) } aria-invalid={!!errors} aria-errormessage={`${name}-error`} /> {errors &&
{errors[0]}
}
); } ``` -------------------------------- ### Define custom empty input values Source: https://formisch.dev/react/guides/create-your-form.md Override default empty values for specific data types to control how fields initialize when empty. ```tsx const loginForm = useForm({ schema: LoginSchema, emptyInput: { string: '', // the default number: 0, // required numbers start at 0 instead of undefined boolean: false, // checkboxes start unchecked }, }); ``` -------------------------------- ### Implement Nested Field Arrays Source: https://formisch.dev/react/guides/field-arrays.md Uses path array syntax to define and render deeply nested field arrays within a form schema. ```tsx const NestedSchema = v.object({ categories: v.array( v.object({ name: v.string(), items: v.array( v.object({ title: v.string(), }) ), }) ), }); {(categoryArray) => ( <> {categoryArray.items.map((categoryItem, categoryIndex) => (
{(field) => } {(itemArray) => ( <> {itemArray.items.map((item, itemIndex) => ( {(field) => } ))} )}
))} )}
; ``` -------------------------------- ### Handle deep nesting in schemas and fields Source: https://formisch.dev/react/guides/nested-fields.md Extend the path array to access fields nested at any depth within the schema object. ```tsx const ProfileSchema = v.object({ user: v.object({ address: v.object({ street: v.string(), city: v.string(), country: v.string(), }), }), }); // Access deeply nested field {(field) => } ; ``` -------------------------------- ### Extract dirty input with getDirtyInput Source: https://formisch.dev/react/guides/dirty-fields.md Retrieves the raw dirty subtree of the form input, useful for PATCH requests. Note that this returns raw input without schema transformations. ```tsx import { Form, getDirtyInput, type SubmitHandler, useForm, } from '@formisch/react'; import * as v from 'valibot'; const UserSchema = v.object({ name: v.pipe(v.string(), v.nonEmpty()), email: v.pipe(v.string(), v.email()), }); export default function EditProfile({ user }) { const profileForm = useForm({ schema: UserSchema, initialInput: user, }); const onSubmit: SubmitHandler = async () => { const dirty = getDirtyInput(profileForm); if (dirty) { await api.patchUser(user.id, dirty); } }; return ( {/* fields */} ); } ``` -------------------------------- ### Implement a boolean checkbox Source: https://formisch.dev/react/guides/special-inputs.md Use a single checkbox to represent a boolean value. ```tsx {(field) => ( )} ``` -------------------------------- ### Source: https://formisch.dev/react/api/Field.md The Field component is a headless component that provides reactive properties and state to its children via a render function. ```APIDOC ## ### Description A headless form field component that provides reactive properties and state. It handles field registration, validation, and state management. ### Usage ```tsx {(fieldStore) => ( fieldStore.setValue(e.target.value)} /> )} ``` ### Properties - **of** (FormStore) - Required - The form store instance. - **path** (TFieldPath) - Required - The path to the specific field within the form. - **children** (Function) - Required - A render function that receives a FieldStore to display field state and handle interactions. ``` -------------------------------- ### Using field.onChange with custom component libraries Source: https://formisch.dev/react/guides/controlled-fields.md Use this pattern when a component library does not expose the underlying native HTML element. The onChange method updates the field value and triggers validation. ```tsx import { DatePicker } from 'some-component-library'; {(field) => ( field.onChange(newDate)} /> )} ; ``` -------------------------------- ### Define a nested schema with Valibot Source: https://formisch.dev/react/guides/nested-fields.md Use v.object to group related fields into nested structures within your schema definition. ```tsx import * as v from 'valibot'; const ContactSchema = v.object({ name: v.object({ first: v.pipe(v.string(), v.nonEmpty()), last: v.pipe(v.string(), v.nonEmpty()), }), email: v.pipe(v.string(), v.email()), message: v.pipe(v.string(), v.nonEmpty()), }); ``` -------------------------------- ### Pass FormStore via Props Source: https://formisch.dev/react/guides/typescript.md Use the FormStore type with your schema to maintain type safety when passing form instances between components. ```tsx import { Form, type FormStore, useForm } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function LoginPage() { const loginForm = useForm({ schema: LoginSchema, }); return ; } type FormContentProps = { of: FormStore; }; function FormContent(props: FormContentProps) { return (
console.log(output)}> {/* Form fields */}
); } ``` -------------------------------- ### Create a reusable FieldError component Source: https://formisch.dev/react/guides/validation.md Encapsulates the error display logic into a reusable component to avoid repetition across fields. ```tsx interface FieldErrorProps { errors: [string, ...string[]] | null; isEdited: boolean; isSubmitted: boolean; } export function FieldError({ errors, isEdited, isSubmitted }: FieldErrorProps) { if (!errors || (!isEdited && !isSubmitted)) { return null; } return
{errors[0]}
; } ``` -------------------------------- ### Implement a custom field component with useField Source: https://formisch.dev/react/guides/add-form-fields.md Use the useField hook to access field state directly within a custom component's logic. This is ideal for creating reusable field components. ```tsx import { useField } from '@formisch/react'; import type { FormStore } from '@formisch/react'; import * as v from 'valibot'; type EmailInputProps = { form: FormStore>; }; function EmailInput(props: EmailInputProps) { const field = useField(props.form, { path: ['email'] }); return (
{field.errors &&
{field.errors[0]}
}
); } ``` -------------------------------- ### Configure Validation Timing Source: https://formisch.dev/react/guides/validation.md Sets the validation triggers for initial field checks and subsequent re-validations. ```tsx const loginForm = useForm({ schema: LoginSchema, validate: 'blur', revalidate: 'input', }); ``` -------------------------------- ### Handle form submission with onSubmit Source: https://formisch.dev/react/guides/handle-submission.md Pass a function to the onSubmit property of the Form component to process validated form values. ```tsx import { Field, Form, useForm } from '@formisch/react'; import type { SubmitHandler } from '@formisch/react'; import * as v from 'valibot'; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function App() { const loginForm = useForm({ schema: LoginSchema, }); const submitForm: SubmitHandler = (values) => { // Process the validated form values console.log(values); // { email: string, password: string } }; return (
{/* Form fields will go here */}
); } ``` -------------------------------- ### Retrieve dirty field paths with getDirtyPaths Source: https://formisch.dev/react/guides/dirty-fields.md Returns an array of paths representing fields that have been modified. Useful for logging or custom state walking. ```tsx import { getDirtyPaths } from '@formisch/react'; const dirtyPaths = getDirtyPaths(profileForm); // e.g. [['email'], ['user', 'name']] ``` -------------------------------- ### Add JSX to TextInput Source: https://formisch.dev/react/guides/input-components.md Provides the full JSX structure for the TextInput component, including label and error handling. ```tsx import type { FieldElementProps } from '@formisch/react'; interface TextInputProps extends FieldElementProps { /* ... */ } export function TextInput({ label, input, errors, ...props }: TextInputProps) { const { name, required } = props; return (
{label && ( )} {errors &&
{errors[0]}
}
); } ``` -------------------------------- ### Send only the dirty raw input Source: https://formisch.dev/react/guides/dirty-fields.md Extract and submit only the raw input values that have changed since the form was initialized. ```tsx import { getDirtyInput } from '@formisch/react'; const dirty = getDirtyInput(form); if (dirty) { await api.patch(dirty); } ``` -------------------------------- ### Trigger submission programmatically Source: https://formisch.dev/react/guides/handle-submission.md Use the submit method to trigger form submission from outside the Form component. ```tsx import { submit } from '@formisch/react'; ; ``` -------------------------------- ### Perform asynchronous form submission Source: https://formisch.dev/react/guides/handle-submission.md Define an async function as the submit handler to perform API calls or other asynchronous operations. ```tsx const submitForm: SubmitHandler = async (values) => { try { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(values), }); if (response.ok) { // Handle successful login console.log('Login successful!'); } else { // Handle error console.error('Login failed'); } } catch (error) { console.error('Error during submission:', error); } }; ``` -------------------------------- ### Implement FieldArray in a React form Source: https://formisch.dev/react/guides/field-arrays.md Uses the FieldArray component to map over todo items and render dynamic input fields for each entry. ```tsx import { Field, FieldArray, Form, useForm } from '@formisch/react'; export default function TodoPage() { const todoForm = useForm({ schema: TodoFormSchema, initialInput: { heading: '', todos: [{ label: '', deadline: '' }], }, }); return (
console.log(output)}> {(field) => ( <> {field.errors &&
{field.errors[0]}
} )}
{(fieldArray) => (
{fieldArray.items.map((item, index) => (
{(field) => ( <> {field.errors &&
{field.errors[0]}
} )}
{(field) => ( <> {field.errors &&
{field.errors[0]}
} )}
))} {fieldArray.errors &&
{fieldArray.errors[0]}
}
)}
); } ``` -------------------------------- ### Access nested fields using path arrays Source: https://formisch.dev/react/guides/nested-fields.md Pass an array of keys to the path property to target specific nested fields within the form. ```tsx {(field) => } ``` -------------------------------- ### Define TextInput properties Source: https://formisch.dev/react/guides/input-components.md Defines the TypeScript interface for the TextInput component, extending FieldElementProps. ```tsx import type { FieldElementProps } from '@formisch/react'; interface TextInputProps extends FieldElementProps { type: 'text' | 'email' | 'tel' | 'password' | 'url' | 'date'; label?: string; placeholder?: string; input: string | undefined; errors: [string, ...string[]] | null; required?: boolean; } ```