--- name: tsh-implementing-forms description: Form architecture, schema-based validation, field composition, error handling, multi-step form flows, and accessible form patterns. Use when building forms, implementing validation, creating multi-step wizards, or integrating form fields with a component library. user-invocable: false --- # Implementing Forms Provides patterns and workflows for building robust, accessible forms with schema-based validation, composable field components, and multi-step form flows. Define validation rules as a separate schema, co-located with but decoupled from UI code. The schema is the single source of truth for what constitutes valid data. Infer TypeScript types from schemas to eliminate drift between validation rules and form types. Never duplicate type definitions manually — derive them from the schema. Show validation errors at the right moment: on field blur or form submission, not on every keystroke. Help users fix errors rather than frustrate them with premature feedback. After the first validation pass, switch to on-change validation so users see errors clear as they correct them. Every form field must have a visible label. Error messages must be announced to screen readers via `role="alert"` or `aria-live` regions. The form must be fully navigable by keyboard alone — Tab through fields, Enter to submit, Escape to cancel where applicable. Associate error messages with their fields using `aria-describedby`. ## Form Implementation Process Use the checklist below and track progress: ``` Progress: - [ ] Step 1: Define the data model - [ ] Step 2: Build field components - [ ] Step 3: Compose the form - [ ] Step 4: Handle multi-step flows (if applicable) - [ ] Step 5: Verify accessibility ``` **Step 1: Define the data model** - Identify all fields: names, types, required vs. optional, default values. - Define a validation schema in a co-located file (`*.schema.ts` or `validation/` directory). The schema declares every constraint: required fields, min/max lengths, patterns, custom rules, cross-field dependencies. - Infer the form's TypeScript type directly from the schema — do not write a separate interface that duplicates the schema's structure. - Document any async validation rules (e.g., "check if username is available") — these run on blur or submit, never on every keystroke. **Step 2: Build field components** Create composable field wrapper components that connect the form library's state to the component library's inputs. Each field wrapper: - Receives the field name (and optionally the form context) as props. - Renders a visible `