Forms
Form layout patterns using Field, react-hook-form, and Zod. Five patterns: single column, two column, with sections, inline compact, horizontal without borders.
react-hook-form + zod + @hookform/resolversField states
Apply data-invalid to Field and aria-invalid to the input — the first turns the label red, the second applies the destructive ring.
Idle, no interaction
disabled — opacity 50%
required on the input element
readOnly — no ring, cursor text
disabled during submit
| State | How to set it | Visual change |
|---|---|---|
| Default | — | Border visible, no ring |
| Focus | focus-visible (browser handles) | ring-1 ring-ring |
| Error | data-invalid on Field + aria-invalid on input | Label red · ring-1 ring-destructive · border-destructive |
| Disabled | disabled on input | opacity-50 · cursor-not-allowed · not interactive |
| Read-only | readOnly on input | Cursor text · no ring on focus · value not editable |
| Pending | disabled on input + button during submit | Same as disabled — re-enable after resolve/reject |
Single column
Vertical field stack. Default pattern for modal and panel forms.
Two column
Two fields per row. Use for related pairs — Status + Priority, Department + Process Step.
With sections
Grouped fields using FieldSet + FieldLegend. Use when a form has 5+ fields that belong to distinct categories.
Inline compact
Horizontal filter bar. No validation — uses useState. NativeSelect preferred over Radix Select for compact toolbars.
Horizontal without borders
Per-field click-to-edit. Icon + label on the left (140px), value on the right. Click value to edit — blur auto-saves. No form submit. Uses HorizontalField.
Company Info
Address
On this page