TextFieldv1.0.0

یک فیلد کامل فرم: برچسب، ورودی، توضیح و پیام خطا در یک کامپوننت، با اتصال خودکار id و aria-describedby. هم به‌صورت میان‌بر (همه چیز با props) و هم به‌صورت ترکیبی (اجزا را خودتان بچینید) کار می‌کند.

ری‌اکت ۱۹ و 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/text-field.json
pnpm dlx digdesign@latest add https://docs.digdesign.ir/r/text-field.json
yarn dlx digdesign@latest add https://docs.digdesign.ir/r/text-field.json
bunx --bun digdesign@latest add https://docs.digdesign.ir/r/text-field.json

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

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

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

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

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

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

استفاده

import {
  TextField,
  TextFieldLabel,
  TextFieldInput,
  TextFieldDescription,
  TextFieldError,
} from "@/components/ui/text-field"

// میان‌بر: همه چیز با props
<TextField
  label="ایمیل"
  type="email"
  description="برای بازیابی رمز لازم است."
  errorMessage="قالب ایمیل درست نیست."
  invalid={hasError}
  required
/>

// ترکیبی: اجزا را خودتان بچینید
<TextField invalid={hasError} required>
  <TextFieldLabel>ایمیل</TextFieldLabel>
  <TextFieldInput type="email" />
  <TextFieldDescription>برای بازیابی رمز لازم است.</TextFieldDescription>
  <TextFieldError>قالب ایمیل درست نیست.</TextFieldError>
</TextField>

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

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

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

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

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

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

ترکیب اجزا

ریشهٔ TextField یک context می‌سازد که id ورودی، id توضیح و id خطا را نگه می‌دارد. به همین دلیل TextFieldLabel خودش htmlFor می‌گیرد و TextFieldInput خودش aria-describedby، aria-invalid و required را برمی‌دارد؛ شما هیچ idای دستی نمی‌نویسید.

وقتی فیلد نامعتبر است، پیام خطا جای توضیح را می‌گیرد، نه اینکه زیرش اضافه شود.

برچسب شناور (labelPlacement="inside") هم کاملاً CSS است: کادر Input کلاس peer می‌گیرد و برچسب با peer-focus-within و peer-data-[filled=true] بالا و پایین می‌رود. پر بودن فیلد را خودِ Input با data-filled اعلام می‌کند، پس هیچ state ری‌اکتی و هیچ اندازه‌گیری در کار نیست.

  • در حالت ترکیبی، TextFieldInput باید در DOM قبل از TextFieldLabel بیاید تا انتخابگر هم‌نیا کار کند.
  • برای فیلد چندخطی به‌جای TextFieldInput از TextFieldTextarea استفاده کنید؛ فقط برچسب شناور را پشتیبانی نمی‌کند.
  • پراپ validate با فیلدِ کنترل‌شده و uncontrolled هر دو کار می‌کند: خطا بعد از اولین ترکِ فیلد نشان داده می‌شود (نه با اولین حرف) و از آن به بعد با هر تغییر به‌روز می‌شود؛ رشته برگرداندن یعنی نامعتبر. برای کد ملی، موبایل و ایمیل از isValidNationalId، isValidMobile و isValidEmail در @/lib/persian استفاده کنید.
  • فیلدِ عددی (inputMode="numeric") حرف نمی‌پذیرد و فیلدِ لاتین (ایمیل، نشانی، کد) رقمِ فارسی را همان‌جا لاتین می‌کند؛ مقداری که به سرور می‌رسد همیشه رقمِ لاتین دارد.

TextField فعلاً فقط برای ری‌اکت پورت شده است.

دسترس‌پذیری

  • برچسب با htmlFor به id ورودی وصل می‌شود؛ id را خودتان ندهید مگر اینکه لازم باشد (useId تولیدش می‌کند).
  • aria-describedby فقط به عنصری اشاره می‌کند که واقعاً رندر شده، اگر توضیح ندهید، اصلاً گذاشته نمی‌شود.
  • پیام خطا role="alert" دارد تا صفحه‌خوان بلافاصله بخواندش.
  • فیلد اجباری علاوه بر ستارهٔ بصری، ویژگی required را روی تگ بومی می‌گذارد تا اعتبارسنجی مرورگر و صفحه‌خوان هر دو بفهمند.
  • در حالت برچسب شناور، placeholder تا لحظهٔ فوکوس پنهان می‌ماند تا با برچسب هم‌پوشانی نکند.

مرجع API

TextField

هر propای که اینجا نیست مستقیم به Input منتقل می‌شود (type، placeholder، variant، color، size، clearable، startContent و…).

ویژگینوعپیش‌فرضتوضیح
labelReact.ReactNode—برچسب فیلد در حالت میان‌بر؛ در حالت ترکیبی به‌جایش TextFieldLabel بگذارید.
labelPlacement"outside" | "outside-top" | "outside-left" | "inside""outside"جایگاه برچسب. outside و outside-top هر دو بالای فیلد؛ inside برچسب شناور داخل کادر.
descriptionReact.ReactNode—متن راهنما زیر فیلد؛ وقتی خطا نمایش داده می‌شود پنهان می‌شود.
errorMessageReact.ReactNode—پیام خطا؛ فقط وقتی invalid روشن باشد دیده می‌شود.
invalidbooleanfalseفیلد نامعتبر است: aria-invalid روی ورودی، برچسب قرمز و نمایش پیام خطا.
validate(value: string) => string | string[] | true | null | undefined—اعتبارسنجی؛ کنترل‌شده یا uncontrolled. بعد از اولین blur نشان داده و بعد زنده به‌روز می‌شود. رشته برگردانید یعنی نامعتبر (همان errorMessage می‌شود)، true/null/undefined یعنی معتبر.
requiredbooleanfalseستارهٔ قرمز کنار برچسب و ویژگی required روی تگ بومی input.
optionalbooleanfalseبرچسب «(اختیاری)» را درست کنار label می‌گذارد؛ با required هم‌زمان نادیده گرفته می‌شود.
disabledbooleanfalseکل فیلد غیرفعال می‌شود.
readOnlybooleanfalseمقدار قابل انتخاب و کپی است ولی تغییر نمی‌کند.
fullWidthbooleantrueفیلد تمام عرض ظرفش را می‌گیرد.
classNamestring—کلاس ظرف بیرونی.
inputClassNamestring—کلاس خودِ تگ input در حالت میان‌بر.
childrenReact.ReactNode—اگر بدهید، حالت ترکیبی فعال می‌شود و propهای میان‌بر (label، description، errorMessage) رندر نمی‌شوند.

TextFieldLabel

روی کامپوننت Label سوار است و htmlFor را خودش از context می‌گیرد.

ویژگینوعپیش‌فرضتوضیح
...propsReact.ComponentProps<typeof Label>—همهٔ propهای Label؛ htmlFor خودکار پر می‌شود ولی می‌توانید بازنویسی کنید.

TextFieldInput

همان Input است با id، aria-invalid، aria-describedby، required، disabled و readOnly از context.

ویژگینوعپیش‌فرضتوضیح
...propsInputProps—همهٔ propهای Input؛ propهای صریح شما بر مقادیر context اولویت دارند.

TextFieldTextarea

همان Textarea است با id، aria-invalid، aria-describedby، required، disabled و readOnly از context؛ برای فیلد چندخطی به‌جای TextFieldInput به‌کار می‌رود. برچسب شناور را پشتیبانی نمی‌کند.

ویژگینوعپیش‌فرضتوضیح
...propsReact.ComponentProps<typeof Textarea>—همهٔ propهای Textarea (از جمله rows)؛ propهای صریح شما بر مقادیر context اولویت دارند.

TextFieldDescription

وقتی پیام خطا نمایش داده می‌شود، خودش را رندر نمی‌کند.

ویژگینوعپیش‌فرضتوضیح
...propsReact.ComponentProps<"p">—id از context می‌آید تا aria-describedby درست بماند.

TextFieldError

فقط وقتی invalid روشن باشد رندر می‌شود و role="alert" دارد.

ویژگینوعپیش‌فرضتوضیح
...propsReact.ComponentProps<"p">—id از context می‌آید تا aria-describedby درست بماند.

Data Attributes

روی ظرف بیرونی می‌نشینند.

ویژگینوعپیش‌فرضتوضیح
data-slot"text-field"—اجزا به‌ترتیب text-field-label، input (یا textarea با TextFieldTextarea)، text-field-description و text-field-error دارند.
data-invalid / data-required / data-disabled / data-readonly"true" | undefined—بازتاب propهای متناظر برای استایل‌دهی از بیرون.

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

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

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

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

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

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