Урок 20. Старый vs Новый: Form против Field

📁 Раздел: shadcn/ui ⏱️ Время изучения: ~55 мин 🎯 Сложность: Продвинутая

⚡ Кратко

Раньше реестр предлагал компонент Form, жёстко связанный с react-hook-form. Теперь обвязка полей вынесена в Field и не зависит от конкретной библиотеки форм.

Обвязка поля

❌ Старый компонент Form

<Form {...form}>
  <form onSubmit={form.handleSubmit(onSubmit)}>
    <FormField
      control={form.control}
      name="email"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Почта</FormLabel>
          <FormControl>
            <Input {...field} />
          </FormControl>
          <FormDescription>Рабочий адрес</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
  </form>
</Form>

Работало хорошо, но привязывало разметку к react-hook-form: контекст, control, рендер-проп на каждое поле.

✅ Field: обвязка отдельно, форма отдельно

<Field data-invalid={!!errors.email}>
  <FieldLabel htmlFor="email">Почта</FieldLabel>
  <Input id="email" aria-invalid={!!errors.email} {...register("email")} />
  <FieldDescription>Рабочий адрес</FieldDescription>
  <FieldError errors={[errors.email]} />
</Field>

Разметка одинакова и для react-hook-form, и для нативной формы, и для любой другой библиотеки: обвязка ничего не знает о том, откуда берутся ошибки.

Сравнение

ПризнакForm (старый)Field (актуальный)
Зависимость от библиотеки формжёсткаянет
Разметка полярендер-пропобычные компоненты
ОшибкиFormMessage из контекстаFieldError errors={[…]}
Горизонтальные полявручнуюorientation="horizontal"
Группы полейвручнуюFieldSet + FieldLegend
Если вы поддерживаете проект, где уже используется старый Form, — переписывать не обязательно. Но новые формы удобнее собирать на Field: меньше связанности и проще тестировать.

Валидация: тогда и сейчас

ЧтоТогдаСейчас
Правилаатрибуты + ручные проверки в обработчикесхема zod
Типыписались отдельноz.infer из схемы
Сообщенияв JSX рядом с полемв схеме, рядом с правилом
Сервер и клиентдублирование правилодна схема на оба конца