Forms

The house form pattern: Zod validation with the right timing, baked in.

Checkbox

The system had no checkbox before this — only DropdownMenuCheckboxItem, which is a menu item. Indeterminate is first-class: a select-all over a partial selection is a real third state (ARIA `mixed`), not a checked box with a different glyph. The hit area grows to 44px on coarse pointers while the box stays 16px.

  • Checkbox

FileInput

A file picker that looks like the system. The native input renders OS chrome that cannot be styled ("Choose File / No file chosen"), so the real input stays in the DOM — it is what makes a plain form submit work with no JavaScript — and is visually hidden behind a surface we own. Drag and drop is supported, and writes back into the real input so the file actually posts.

  • FileInput
  • Label

Pick a file or drag one on — the surface shows the name and size, and the clear button appears only once something is selected.

Textarea

Multi-line text, sharing Input’s exact border, radius and focus ring — a form holding both should not look assembled from two libraries. Base UI ships no textarea primitive, so this wraps the native element; it needs no popup or state machine and still participates in a Field through plain id/name. `field-sizing-content` grows the box with the text, and the drag handle is OFF by default because a resizable box inside a card gets dragged over whatever sits beside it.

  • Textarea
  • Label

useZodForm

The canonical form: a Zod schema drives TanStack Form with validate-on-submit then revalidate-on-change. Live — submit empty, then fix a field.

  • Input
  • Label
  • Button

The house timing, baked into useZodForm: nothing is flagged until the first submit, then every field revalidates as you type — errors clear the moment the input is fixed. Submit empty to see it.