TextField
یک فیلد کامل فرم: برچسب، ورودی، توضیح و پیام خطا در یک کامپوننت، با اتصال خودکار id و aria-describedby. هم بهصورت میانبر (همه چیز با props) و هم بهصورت ترکیبی (اجزا را خودتان بچینید) کار میکند.
این کامپوننت فعلاً برای ۱ فریمورک از ۴ فریمورک آماده است.
هیچوقت ایمیلتان را با کسی به اشتراک نمیگذاریم.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
نصب
با CLI اختصاصی dig-ui کامپوننت را از رجیستری دیگ نصب کنید؛ وابستگیها و فایلها خودکار اضافه میشوند.
pnpm dlx dig-ui@latest add https://design-system-tau-green.vercel.app/r/text-field.jsonnpx dig-ui@latest add https://design-system-tau-green.vercel.app/r/text-field.jsonyarn dlx dig-ui@latest add https://design-system-tau-green.vercel.app/r/text-field.jsonbunx --bun dig-ui@latest add https://design-system-tau-green.vercel.app/r/text-field.jsonاین کامپوننت هنوز برای Vue پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Reka UI در دست کار است.
این کامپوننت هنوز برای Svelte پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Bits UI در دست کار است.
این کامپوننت هنوز برای Angular پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Angular CDK در دست کار است.
استفاده
import { TextField } from "@/components/ui/text-field"
// میانبر: همه چیز با props
<TextField
label="ایمیل"
type="email"
description="برای بازیابی رمز لازم است."
errorMessage="قالب ایمیل درست نیست."
invalid={hasError}
required
/>
// ترکیبی: اجزا را خودتان بچینید
import {
TextField,
TextFieldLabel,
TextFieldInput,
TextFieldDescription,
TextFieldError,
} from "@/components/ui/text-field"
<TextField invalid={hasError} required>
<TextFieldLabel>ایمیل</TextFieldLabel>
<TextFieldInput type="email" />
<TextFieldDescription>برای بازیابی رمز لازم است.</TextFieldDescription>
<TextFieldError>قالب ایمیل درست نیست.</TextFieldError>
</TextField>این کامپوننت هنوز برای Vue پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Reka UI در دست کار است.
این کامپوننت هنوز برای Svelte پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Bits UI در دست کار است.
این کامپوننت هنوز برای Angular پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Angular CDK در دست کار است.
ترکیب اجزا
ریشهٔ 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هم هست: تابعی که با هر تغییر مقدار صدا زده میشود و رشته برگرداندن یعنی نامعتبر، دیگر لازم نیستinvalidوerrorMessageرا دستی هماهنگ نگه دارید.
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 | — | اعتبارسنجی زنده روی مقدار کنترلشده؛ رشته برگردانید یعنی نامعتبر (همان errorMessage میشود)، true/null/undefined یعنی معتبر. فقط با value کنترلشده اجرا میشود. |
| required | boolean | false | ستارهٔ قرمز کنار برچسب و ویژگی required روی تگ بومی input. |
| 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 پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Reka UI در دست کار است.
این کامپوننت هنوز برای Svelte پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Bits UI در دست کار است.
این کامپوننت هنوز برای Angular پورت نشده است.
نسخهٔ ریاکت آماده است؛ پورت این فریمورک روی Angular CDK در دست کار است.
نمونهها
Label Placements
چهار جایگاه برچسب. outside و outside-top هر دو برچسب را بالای فیلد میگذارند (دیگ برای outside انیمیشن شناور ندارد و آن را ثابت رندر میکند)؛ inside برچسب را داخل کادر میبرد و با فوکوس یا پرشدن فیلد بالا میرود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
With Description
توضیح زیر فیلد میآید و خودکار با aria-describedby به ورودی وصل میشود.
فقط حروف لاتین، عدد و خط تیره. بعداً قابل تغییر است.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Required
با required یک ستارهٔ قرمز کنار برچسب میآید و ویژگی required روی تگ بومی مینشیند.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
With Error Message
با invalid پیام خطا جای توضیح را میگیرد، برچسب قرمز میشود و aria-invalid روی ورودی مینشیند.
قالب ایمیل درست نیست.
این توضیح وقتی خطا هست پنهان میشود.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Realtime Validation
اعتبارسنجی زنده: تا وقتی مقدار درست نشده، خطا نمایش داده میشود.
قالب ایمیل درست نیست؛ مثلاً armita@dig.ir.
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
Built-in Validation (validate)
بهجای هماهنگنگهداشتن دستیِ invalid و errorMessage، پراپ validate را روی مقدار کنترلشده بدهید؛ رشته برگردانید یعنی نامعتبر (همان پیام خطا میشود)، null یا true یعنی معتبر، همان قرارداد validate در React Aria.
قالب ایمیل درست نیست؛ مثلاً armita@dig.ir.
این نمونه هنوز برای 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" بدهید و ارقام را همعرض کنید تا خوانا بماند.
مقدار بلند داخل فیلد اسکرول میشود، فیلد پهن نمیشود
دادهٔ لاتین با dir=ltr و ارقام همعرض خوانا میماند
این نمونه هنوز برای Vue پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Svelte پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
این نمونه هنوز برای Angular پورت نشده است؛ آنچه میبینید نسخهٔ ریاکت است.
کدام نمونه برای کدام موقعیت
| نمونه | کجا به کار میآید |
|---|---|
| Label Placements | چهار جایگاه برچسب |
| With Description | توضیح زیر فیلد میآید و خودکار با aria-describedby به ورودی وصل میشود. |
| Required | با required یک ستارهٔ قرمز کنار برچسب میآید و ویژگی required روی تگ بومی مینشیند. |
| With Error Message | با invalid پیام خطا جای توضیح را میگیرد، برچسب قرمز میشود و aria-invalid روی ورودی مینشیند. |
| Realtime Validation | اعتبارسنجی زنده: تا وقتی مقدار درست نشده، خطا نمایش داده میشود. |
| Built-in Validation (validate) | بهجای هماهنگنگهداشتن دستیِ invalid و errorMessage، پراپ validate را روی مقدار کنترلشده بدهید؛ رشته برگردانید یعنی نامعتبر (همان پیام خطا میشود)، null یا true یعنی معتبر، همان قرارداد validate در React Aria. |
| 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، اعتبارسنجی مرورگر و اعلام صفحهخوان را از دست میدهد؛ کاربر باید فقط به متن اعتماد کند.