---
name: forms
description: "Use when: creating or modifying TanStack Form components, field layouts, validation schemas, submit handling, or custom form controls."
---

# Form Patterns

## Rules

- Always use `useLayoutForm` with pre-defined components.
- Define `width` for all form fields based on the expected content length.
- Reuse Zod schemas from `src/lib/schemas/` which are derived from Drizzle schemas with `createSelectSchema` from table schemas.
- Use translation for labels, helper text, validation messages and submit.
- Reset the form after successful create.
- Use one of the following field based on the use case: `Autocomplete`, `Checkbox`, `DatePicker`, `DateRangePicker`, `DateTimePicker`, `DateTimeRangePicker`, `NumberField`, `RadioGroup`, `Slider`, `SubmitButton`, `Switch`, `TextField`, `TimePicker`, or `TimeRangePicker`.

## File Placement

```
src/routes/<feature>s/-components/ - route-scoped forms
src/lib/schemas/                   — Zod schemas (shared between client and server)
wcz-layout/hooks                   - useLayoutForm hook, useTranslation
```

## Examples

```ts
// Form Component
interface FormProps {
  defaultValues: Feature;
  onSubmit: (value: Feature) => Promise<void>;
}

export const Form: FC<FormProps> = ({ defaultValues, onSubmit }) => {
  const { t } = useTranslation();

  const form = useLayoutForm({
    defaultValues,
    validators: { onChange: FeatureSchema },
    onSubmit: async ({ value, formApi }) => {
      await onSubmit(value);
      formApi.reset();
    },
  });

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        event.stopPropagation();
        form.handleSubmit();
      }}
    >
      {/* some styling */}
      <form.AppField name="name">
        {(field) => <field.TextField label={t("Feature.Name")} required sx={{ width: 420 }} />}
      </form.AppField>
      {/* some styling */}
      <form.AppForm>
        <form.SubmitButton variant="contained">{t("Submit")}</form.SubmitButton>
      </form.AppForm>
    </form>
  );
};

// Autocomplete
<field.Autocomplete
  options={options}
  sx={{ width: 250 }}
  autoHighlight
  autoSelect
  autoComplete
  loading={isLoading}
  textFieldProps={{
    label: t("Customer"),
    required: true,
  }}
/>

// Checkbox
<field.Checkbox label={t("IsThisTrue")} />
```
