TextFieldv1.0.0
یک فیلد کامل فرم: برچسب، ورودی، توضیح و پیام خطا در یک کامپوننت، با اتصال خودکار id و aria-describedby. هم بهصورت میانبر (همه چیز با props) و هم بهصورت ترکیبی (اجزا را خودتان بچینید) کار میکند.
این کامپوننت فعلاً برای ۱ فریمورک از ۴ فریمورک آماده است.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
نصب
با CLI اختصاصی digdesign کامپوننت را از رجیستری دیگ نصب کنید؛ وابستگیها و فایلها خودکار اضافه میشوند.
npx digdesign@latest add https://docs.digdesign.ir/r/text-field.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/text-field.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/text-field.jsonbunx --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 و…).
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
| label | React.ReactNode | — | برچسب فیلد در حالت میانبر؛ در حالت ترکیبی بهجایش TextFieldLabel بگذارید. |
| labelPlacement | "outside" | "outside-top" | "outside-left" | "inside" | "outside" | جایگاه برچسب. outside و outside-top هر دو بالای فیلد؛ inside برچسب شناور داخل کادر. |
| description | React.ReactNode | — | متن راهنما زیر فیلد؛ وقتی خطا نمایش داده میشود پنهان میشود. |
| errorMessage | React.ReactNode | — | پیام خطا؛ فقط وقتی invalid روشن باشد دیده میشود. |
| invalid | boolean | false | فیلد نامعتبر است: aria-invalid روی ورودی، برچسب قرمز و نمایش پیام خطا. |
| validate | (value: string) => string | string[] | true | null | undefined | — | اعتبارسنجی؛ کنترلشده یا uncontrolled. بعد از اولین blur نشان داده و بعد زنده بهروز میشود. رشته برگردانید یعنی نامعتبر (همان errorMessage میشود)، true/null/undefined یعنی معتبر. |
| required | boolean | false | ستارهٔ قرمز کنار برچسب و ویژگی required روی تگ بومی input. |
| optional | boolean | false | برچسب «(اختیاری)» را درست کنار label میگذارد؛ با required همزمان نادیده گرفته میشود. |
| disabled | boolean | false | کل فیلد غیرفعال میشود. |
| readOnly | boolean | false | مقدار قابل انتخاب و کپی است ولی تغییر نمیکند. |
| fullWidth | boolean | true | فیلد تمام عرض ظرفش را میگیرد. |
| className | string | — | کلاس ظرف بیرونی. |
| inputClassName | string | — | کلاس خودِ تگ input در حالت میانبر. |
| children | React.ReactNode | — | اگر بدهید، حالت ترکیبی فعال میشود و propهای میانبر (label، description، errorMessage) رندر نمیشوند. |
TextFieldLabel
روی کامپوننت Label سوار است و htmlFor را خودش از context میگیرد.
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
| ...props | React.ComponentProps<typeof Label> | — | همهٔ propهای Label؛ htmlFor خودکار پر میشود ولی میتوانید بازنویسی کنید. |
TextFieldInput
همان Input است با id، aria-invalid، aria-describedby، required، disabled و readOnly از context.
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
| ...props | InputProps | — | همهٔ propهای Input؛ propهای صریح شما بر مقادیر context اولویت دارند. |
TextFieldTextarea
همان Textarea است با id، aria-invalid، aria-describedby، required، disabled و readOnly از context؛ برای فیلد چندخطی بهجای TextFieldInput بهکار میرود. برچسب شناور را پشتیبانی نمیکند.
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
| ...props | React.ComponentProps<typeof Textarea> | — | همهٔ propهای Textarea (از جمله rows)؛ propهای صریح شما بر مقادیر context اولویت دارند. |
TextFieldDescription
وقتی پیام خطا نمایش داده میشود، خودش را رندر نمیکند.
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
| ...props | React.ComponentProps<"p"> | — | id از context میآید تا aria-describedby درست بماند. |
TextFieldError
فقط وقتی invalid روشن باشد رندر میشود و role="alert" دارد.
| ویژگی | نوع | پیشفرض | توضیح |
|---|---|---|---|
| ...props | React.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 پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک در دست کار است.
نمونهها
فیلدهای بانکی: مبلغ، شماره کارت، تاریخ انقضا
این فیلدها کامپوننت جدا ندارند؛ تنظیم درست TextField کافی است. مبلغ با inputMode="numeric" و groupDigits ارقام فارسی و جداکنندهٔ هزارگان میگیرد ولی مقدار لاتین بدون جداکننده میفرستد. شماره کارت با digitGroups={[4, 4, 4, 4]} چهارتا چهارتا دیده میشود و BankLogo در endContent بانک را با ۶ رقمِ اول نشان میدهد؛ مقدار ۱۶ رقمِ بیفاصله است. انقضا دو فیلد دورقمی ماه و سال است.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Label Placements
چهار جایگاه برچسب. outside و outside-top هر دو برچسب را بالای فیلد میگذارند (دیگ برای outside انیمیشن شناور ندارد و آن را ثابت رندر میکند)؛ inside برچسب را داخل کادر میبرد و با فوکوس یا پرشدن فیلد بالا میرود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
With Description
توضیح زیر فیلد میآید و خودکار با aria-describedby به ورودی وصل میشود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Required
با required یک ستارهٔ قرمز کنار برچسب میآید و ویژگی required روی تگ بومی مینشیند.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Optional
با optional عبارت «(اختیاری)» بلافاصله کنار برچسب میآید. وقتی بیشتر فیلدها اجباریاند، بهجای ستاره روی همه، همین را روی چندتای اختیاری بگذارید.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
With Error Message
با invalid پیام خطا جای توضیح را میگیرد، برچسب قرمز میشود و aria-invalid روی ورودی مینشیند.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Realtime Validation
اعتبارسنجی زنده: تا وقتی مقدار درست نشده، خطا نمایش داده میشود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Built-in Validation (validate)
بهجای هماهنگنگهداشتن دستیِ invalid و errorMessage، پراپ validate را بدهید؛ رشته برگردانید یعنی نامعتبر (همان پیام خطا میشود)، null یا true یعنی معتبر. خطا بعد از اولین ترکِ فیلد ظاهر میشود تا فیلدِ نیمهکاره قرمز نشود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
With Textarea
برای فیلد چندخطی بهجای TextFieldInput از TextFieldTextarea استفاده کنید؛ اتصال id و aria همچنان خودکار است. برچسب شناور (labelPlacement="inside") برای این حالت پشتیبانی نمیشود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
With Form
چون ورودی همان تگ بومی است، name و required و minLength مستقیم به فرم میرسند؛ اینجا اعتبارسنجی مرورگر خاموش شده تا پیام خودمان نمایش داده شود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Controlled
onValueChange مقدار متنی میدهد؛ اینجا از آن برای شمارندهٔ نویسه در توضیح استفاده شده.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Composition
اگر ترتیب یا محتوای اجزا را میخواهید خودتان بچینید، بهجای propهای میانبر از اجزا استفاده کنید؛ اتصال id و aria همچنان خودکار است.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Input Options
هر propای که TextField نمیشناسد مستقیم به Input میرسد، پس واریانت، رنگ، اندازه، محتوای ابتدا/انتها و دکمهٔ پاککردن همه در دسترساند.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Disabled and Read-only
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Full Width
پیشفرض تمامعرض است؛ برای فیلد کوتاه fullWidth را خاموش کنید.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
در حال بررسی (Loading)
وقتی مقدار در حال اعتبارسنجی سمت سرور است، فیلد را قفل کنید ولی مقدارش را خوانا نگه دارید و با aria-busy به صفحهخوان بگویید منتظر است. متن راهنما جای خوبی برای گفتن وضعیت است.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
خالی (Empty)
placeholder جای label نیست. با شروع تایپ ناپدید میشود و کاربر دیگر نمیداند این فیلد چیست. لیبل ماندگار بگذارید و اگر راهنما لازم است، در description بنویسید نه در placeholder.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
متن بلند و دادههای لاتین (Overflow)
مقدار طولانی داخل فیلد اسکرول میشود و فیلد پهن نمیشود، پس چیدمان فرم نمیشکند. برای دادههای لاتین مثل شناسه و ایمیل، dir="ltr" بدهید و ارقام را همعرض کنید تا خوانا بماند.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
کدام نمونه برای کدام موقعیت
| نمونه | کجا به کار میآید |
|---|---|
| فیلدهای بانکی: مبلغ، شماره کارت، تاریخ انقضا | انتقال وجه، پرداخت و افزودن کارت |
| Label Placements | چهار جایگاه برچسب |
| With Description | توضیح زیر فیلد میآید و خودکار با aria-describedby به ورودی وصل میشود. |
| Required | با required یک ستارهٔ قرمز کنار برچسب میآید و ویژگی required روی تگ بومی مینشیند. |
| Optional | فرمی که بیشتر فیلدهایش اجباری است و فقط چندتا اختیاری |
| With Error Message | با invalid پیام خطا جای توضیح را میگیرد، برچسب قرمز میشود و aria-invalid روی ورودی مینشیند. |
| Realtime Validation | اعتبارسنجی زنده: تا وقتی مقدار درست نشده، خطا نمایش داده میشود. |
| Built-in Validation (validate) | بهجای هماهنگنگهداشتن دستیِ invalid و errorMessage، پراپ validate را بدهید؛ رشته برگردانید یعنی نامعتبر (همان پیام خطا میشود)، null یا true یعنی معتبر |
| With Textarea | برای فیلد چندخطی بهجای TextFieldInput از TextFieldTextarea استفاده کنید؛ اتصال id و aria همچنان خودکار است |
| With Form | چون ورودی همان تگ بومی است، name و required و minLength مستقیم به فرم میرسند؛ اینجا اعتبارسنجی مرورگر خاموش شده تا پیام خودمان نمایش داده شود. |
| Controlled | onValueChange مقدار متنی میدهد؛ اینجا از آن برای شمارندهٔ نویسه در توضیح استفاده شده. |
| Composition | اگر ترتیب یا محتوای اجزا را میخواهید خودتان بچینید، بهجای propهای میانبر از اجزا استفاده کنید؛ اتصال id و aria همچنان خودکار است. |
| Input Options | هر propای که TextField نمیشناسد مستقیم به Input میرسد، پس واریانت، رنگ، اندازه، محتوای ابتدا/انتها و دکمهٔ پاککردن همه در دسترساند. |
| Disabled and Read-only | مقداری که در پلن فعلی قابل تغییر نیست یا فقط قابل کپی است |
| Full Width | پیشفرض تمامعرض است؛ برای فیلد کوتاه fullWidth را خاموش کنید. |
| در حال بررسی (Loading) | بررسی یکتا بودن شناسه در سرور |
| خالی (Empty) | هر فرمی که بیش از دو فیلد دارد |
| متن بلند و دادههای لاتین (Overflow) | شناسه، ایمیل، و عنوان بلند |
دستورالعمل استفاده
همیشه label بدهید، نه فقط placeholder
انجام بده
با پراپ label یک برچسب واقعی و همیشه دیدهشدنی بسازید تا کاربر پیش و پس از تایپ بداند این فیلد چیست.
انجام نده
اگر فقط placeholder بگذارید و label ندهید، بهمحض شروع تایپ یا با labelPlacement="inside" پس از فوکوس، تنها راهنمای فیلد ناپدید میشود و کاربر جا میماند این چه فیلدی بود.
پیام خطا مشخص و راهگشا باشد
قالب ایمیل درست نیست؛ مثلاً armita@dig.ir.
انجام بده
errorMessage باید بگوید مشکل چیست و چطور درستش کنیم؛ چون با invalid جای description را میگیرد، تنها چیزی است که کاربر در آن لحظه میبیند.
خطا
انجام نده
پیام مبهم مثل «خطا» یا «نامعتبر» به کاربر نمیگوید چه چیزی را باید تغییر دهد.
required فقط برای فیلدهای واقعاً اجباری
انجام بده
required هم ستارهٔ بصری کنار برچسب میگذارد و هم ویژگی required را روی input مینشاند؛ فقط برای فیلدی بدهید که واقعاً پر کردنش لازم است.
انجام نده
نوشتن «(اجباری)» داخل متن label بدون دادن پراپ required، اعتبارسنجی مرورگر و اعلام صفحهخوان را از دست میدهد؛ کاربر باید فقط به متن اعتماد کند.