Formv1.0.0

Form خودش هیچ ورودی‌ای رندر نمی‌کند؛ فقط context مربوط به react-hook-form را پخش می‌کند و FormField/FormItem/FormLabel/FormControl/FormMessage را به هم و به id/aria درست وصل می‌کند. اعتبارسنجی با هر resolver ای از جمله zod کار می‌کند.

ری‌اکت ۱۹ و Next.js با پیاده‌سازی دسترس‌پذیری داخلی دیگویو ۳ با Composition API — هنوز برای این کامپوننت پورت نشدهSvelte ۵ با runes — هنوز برای این کامپوننت پورت نشدهانگولار با signals و دایرکتیوهای standalone — هنوز برای این کامپوننت پورت نشده

این کامپوننت فعلاً برای ۱ فریم‌ورک از ۴ فریم‌ورک آماده است.

همان چیزی که در پروفایل عمومی نشان داده می‌شود.

این نمونه هنوز برای Vue پورت نشده است؛ آنچه می‌بینید نسخهٔ ری‌اکت است.

این نمونه هنوز برای Svelte پورت نشده است؛ آنچه می‌بینید نسخهٔ ری‌اکت است.

این نمونه هنوز برای Angular پورت نشده است؛ آنچه می‌بینید نسخهٔ ری‌اکت است.

نصب

با CLI اختصاصی digdesign کامپوننت را از رجیستری دیگ نصب کنید؛ وابستگی‌ها و فایل‌ها خودکار اضافه می‌شوند.

پکیج‌منیجر پیش‌فرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیج‌منیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/form.json
pnpm dlx digdesign@latest add https://docs.digdesign.ir/r/form.json
yarn dlx digdesign@latest add https://docs.digdesign.ir/r/form.json
bunx --bun digdesign@latest add https://docs.digdesign.ir/r/form.json

این کامپوننت هنوز برای Vue پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

این کامپوننت هنوز برای Svelte پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

این کامپوننت هنوز برای Angular پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

استفاده

import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"

import { Button } from "@/components/ui/button"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"

const formSchema = z.object({
  username: z.string().min(2),
})

function ProfileForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: { username: "" },
  })

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(console.log)}>
        <FormField
          control={form.control}
          name="username"
          render={({ field }) => (
            <FormItem>
              <FormLabel>نام کاربری</FormLabel>
              <FormControl>
                <Input {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">ذخیره</Button>
      </form>
    </Form>
  )
}

این کامپوننت هنوز برای Vue پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

این کامپوننت هنوز برای Svelte پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

این کامپوننت هنوز برای Angular پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

ترکیب اجزا

FormField یک react-hook-form Controller است که name فیلد را در FormFieldContext می‌گذارد؛ FormItem یک id تازه با useId می‌سازد و در FormItemContext می‌گذارد.

useFormField این دو context را با getFieldState ترکیب می‌کند و id، formItemId، formDescriptionId، formMessageId و وضعیت خطا را برمی‌گرداند.

FormLabel از formItemId به‌عنوان htmlFor استفاده می‌کند، FormControl همان id را به کنترل واقعی می‌دهد و aria-describedby را بسته به وجود خطا به FormDescription و/یا FormMessage وصل می‌کند.

یعنی کافی‌ست این چهار تکه را همیشه با هم داخل FormItem بگذارید؛ بقیه (اتصال id، اعلام خطا به صفحه‌خوان) خودکار است.

برای فرم‌های چندبخشی، FormFieldها را داخل Fieldset بگذارید: Form مسئول اعتبارسنجی/خطا می‌ماند، Fieldset فقط گروه‌بندی معنایی (legend) و چیدمان می‌دهد.

دسترس‌پذیری

  • FormControl خودش aria-invalid و aria-describedby را روی کنترل واقعی ست می‌کند؛ کافی‌ست کنترل را (Input، Select، Checkbox و…) مستقیم داخلش بگذارید، نیازی به نوشتن دستی این پراپ‌ها نیست.
  • FormLabel با data-error={true} رنگ خودش را قرمز می‌کند، اما این فقط بصری است؛ اعلام واقعی خطا به صفحه‌خوان از طریق aria-describedby روی FormControl و متن FormMessage انجام می‌شود.
  • FormMessage وقتی خطایی نیست چیزی رندر نمی‌کند (نه یک <p> خالی)؛ پس فضای خالی برای پیام خطا در DOM نمی‌ماند تا صفحه‌خوان چیزی خالی را اعلام کند.
  • برای فیلدهایی که خودشان id ندارند (مثل Select یا Checkbox)، همان الگوی FormControl کافی است؛ خودِ FormControl از طریق Slot، id و aria را به اولین فرزندش تزریق می‌کند.
  • با ارسال ناموفق، react-hook-form به‌صورت پیش‌فرض فوکوس را به اولین فیلدِ دارای خطا می‌برد (shouldFocusError)، تا وقتی FormControl، ref کنترل واقعی را درست پاس بدهد (که خودش این کار را می‌کند)، نیازی به مدیریت دستی فوکوس نیست.

مرجع API

Form

ویژگینوعپیش‌فرضتوضیح
...formUseFormReturn<T>—خروجی useForm همینجا اسپرد می‌شود؛ Form پشت‌پرده FormProvider را با همین مقدار رندر می‌کند.
errorsPartial<Record<FieldPath<T>, string>>—خطاهای سمت سرور، کلید = نام فیلد. روی همان فیلد ست می‌شود و با اولین تغییر کاربر در آن فیلد خودکار پاک می‌شود؛ خطاهای معمولیِ resolver/rules را دست‌نخورده می‌گذارد.

FormField

ویژگینوعپیش‌فرضتوضیح
controlControl<T>—همان form.control از useForm.
nameFieldPath<T>—مسیر فیلد در schema/defaultValues.
render({ field, fieldState }) => ReactNode—همان الگوی Controller از react-hook-form؛ field شامل value، onChange، onBlur، ref و name است.

useFormField()

ویژگینوعپیش‌فرضتوضیح
errorFieldError | undefined—خطای اعتبارسنجی فیلد جاری، اگر باشد.
formItemId / formDescriptionId / formMessageIdstring—idهایی که FormLabel/FormControl/FormDescription/FormMessage برای اتصال aria از همین می‌خوانند.

این کامپوننت هنوز برای Vue پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

این کامپوننت هنوز برای Svelte پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.

این کامپوننت هنوز برای Angular پورت نشده است.

نسخهٔ ری‌اکت آماده است؛ پورت این فریم‌ورک در دست کار است.