---
title: "حقل النص"
description: "يتيح للأشخاص إدخال نص وتحريره، سطرًا واحدًا أو عدة أسطر تتبع النص أو يُغيَّر حجمها باليد، أو إدخال تاريخ أو وقت وحدةً وحدةً بصيغة الإعدادات المحلية، أو شيفرة تُحفظ كما كُتبت تمامًا، مع تسمية تستطيع أن تقول إن الحقل مطلوب أو اختياري، وأيقونات اختيارية، وبادئة ولاحقة، ونص مساعد، وعدّاد أحرف، وزر منتقٍ."
url: "https://tanrei.chnotchy.com/ar/components/text-field/"
last_updated: 2026-10-26T22:31:32.000Z
---

# حقل النص

> يتيح للأشخاص إدخال نص وتحريره، سطرًا واحدًا أو عدة أسطر تتبع النص أو يُغيَّر حجمها باليد، أو إدخال تاريخ أو وقت وحدةً وحدةً بصيغة الإعدادات المحلية، أو شيفرة تُحفظ كما كُتبت تمامًا، مع تسمية تستطيع أن تقول إن الحقل مطلوب أو اختياري، وأيقونات اختيارية، وبادئة ولاحقة، ونص مساعد، وعدّاد أحرف، وزر منتقٍ.

## نظرة عامة

> [!NOTE]
> **مواصفة معدَّلة، لم تصل بعد إلى كل منصة**
>
> تصف هذه الصفحة حقل النص كما هو في المواصفة الآن: طراز (variant) هو `stacked`، وهو الافتراضي، وتسميته فوق الحقل؛ والطرازان `filled` و `outlined` باقيان لإعدادات Material الجاهزة والإعداد الجاهز cupertino فقط؛ وثلاثة ارتفاعات هي 32 و 40 و 56 (و 40 و 48 و 56 للحقل من الطراز filled أو outlined، الذي تعوم تسميته داخله)؛ وأنواع للتاريخ والوقت، مع زر منتقٍ؛ وحقل متعدد الأسطر يتبع نصه أو يُغيَّر حجمه بمقبض (`resize`)؛ وتاريخ أو وقت يُدخل وحدةً وحدةً، في مقاطع؛ والخاصيتان `required` و `optional` اللتان تعلّمان الحقل بأنه مطلوب أو اختياري. مكوّن الويب يفعل ذلك كله منذ الآن، وكذلك العروض التوضيحية. ويمكن للحقل أيضًا أن يحمل شيفرة (`type="code"`، ومعه `wrap` لأسطرها): بناه الويب، ولم تبنِه أي منصة أخرى بعد. وحقل النص حقل حول حقل إدخال النص، كما تصفه هذه الصفحة: بنى الويب ذلك أيضًا، وزالت فيه خاصية HTML `required`. أما SwiftUI و Compose و Flutter و React Native فموسومة أعلاه بأنها متأخرة: إلى أن تلحق تقدّم المراجعة السابقة، وهي من الطراز outlined افتراضيًّا بارتفاعي 36 و 40، وفيها راية `required` لا ترسم علامة، وليس فيها الطراز `stacked` ولا أنواع التاريخ والوقت ولا زر المنتقي ولا أوضاع تغيير الحجم، وتعرض عيّناتها تلك المراجعة.

استخدم حقل النص حيثما يطلب النموذج نصًّا: فهو الحالة المعتادة، جاهزًا للاستخدام، بتسمية، وصندوق، وسطر مساعدة، والكلمات التي تقول إن القيمة خاطئة، وعدد.

**يُبنى من** [حقل](https://tanrei.chnotchy.com/ar/components/field/) و [حقل إدخال النص](https://tanrei.chnotchy.com/ar/components/text-input/). الحقل هو الإطار: التسمية، وعلامة المطلوب أو الاختياري، والمساعدة، والخطأ، والعدد. وحقل إدخال النص هو عنصر التحكم: الصندوق وكل ما يُكتب فيه. وحقل النص لا يرسم شيئًا من عنده وليس له أي رمز تصميم (token): فكل خاصية له هي خاصية لأحد الاثنين، تُعطى له كما هي.

هو كتلة بعرض المكان الذي يوضع فيه، وصندوقه يملؤه. وليس له عرض من عنده: فلحقل أضيق أعطِه مكانًا أضيق.

### الاستخدام

**Web**

```html
<form>
  <tanrei-text-field name="email" label="البريد الإلكتروني" type="email" autocomplete="email" required required-text="مطلوب"
    supporting-text="نستخدمه لتسجيل دخولك فقط."></tanrei-text-field>
  <tanrei-text-field name="company" label="الشركة" optional optional-text="اختياري"></tanrei-text-field>
  <!-- يتبع نصه من 3 أسطر إلى 8، ثم يُمرَّر. -->
  <tanrei-text-field name="message" label="الرسالة" multiline min-rows="3" max-rows="8"></tanrei-text-field>
  <!-- يُغيَّر حجمه باليد، بمقبض. -->
  <tanrei-text-field name="notes" label="الملاحظات" multiline resize="manual" resize-label="تغيير حجم الملاحظات"></tanrei-text-field>
</form>

<!-- الصندوق وحده، في شريط أدوات: حقل إدخال النص، وتسمّيه label الخاصة به. واستيراد حقل النص يعرّفه. -->
<tanrei-text-input label="بحث" type="search" placeholder="ابحث في المكوّنات">
  <span slot="leading-icon">search</span>
</tanrei-text-input>

<!-- شيفرة: من اليسار إلى اليمين وبخط الشيفرة في كل اتجاه للصفحة، ولا تُصحَّح ولا تُدقَّق إملائيًّا أبدًا. -->
<tanrei-text-field label="النمط" type="code" value="tanrei.comp.button.*.container.color"></tanrei-text-field>
<tanrei-text-field label="محتوى طلب Webhook" type="code" multiline min-rows="4" supporting-text="JSON"></tanrei-text-field>
<!-- بلا التفاف: كل سطر من الشيفرة يبقى في سطر واحد، والسطر الطويل يُمرَّر داخل الحقل. -->
<tanrei-text-field label="الصفوف" type="code" multiline no-wrap></tanrei-text-field>

<!-- تاريخ يُدخل وحدةً وحدةً بترتيب الإعدادات المحلية، ويُحفظ في الصورة 2026-09-27، مع زر منتقٍ. -->
<tanrei-text-field id="start" label="تاريخ البدء" type="date" min="2026-01-01" disabled-dates="2026-05-01 2026-12-25"
  invalid-text="أكمِل التاريخ." unavailable-text="اختر يوم عمل في 2026 أو بعدها."
  picker picker-label="اختيار تاريخ البدء" segment-empty-text="فارغ"></tanrei-text-field>
<tanrei-date-time-picker id="start-picker" presentation="docked" anchor="start" label="تاريخ البدء"></tanrei-date-time-picker>

<script type="module">
  import '@tanrei/web/components/text-field';
  const email = document.querySelector('[name="email"]');
  email.addEventListener('input', () => draft(email.value)); // كل تعديل
  email.addEventListener('change', () => save(email.value)); // غادر التركيز أو ضُغط Enter، والقيمة تغيّرت
  // التحقق من شأنك: الحقل لا يعيّن error بنفسه أبدًا.
  email.error = submitted && !isValid(email.value);
  email.errorText = 'أدخِل عنوان بريد إلكتروني كاملًا.';

  // الحقل يطلب؛ والمنتج يعرض المنتقي ويكتب القيمة في الحقل.
  const start = document.querySelector('#start');
  const picker = document.querySelector('#start-picker');
  start.addEventListener('pickerrequest', (e) => {
    Object.assign(picker, { value: e.detail.value, min: e.detail.min, max: e.detail.max, disabledDates: start.disabledDates, open: true });
  });
  picker.addEventListener('change', () => (start.value = picker.value));
  picker.addEventListener('close', () => (picker.open = false));
</script>
```

**React**

```tsx
import { TextField } from '@tanrei/react';

<TextField
  label="البريد الإلكتروني"
  type="email"
  autocomplete="email"
  value={email}
  onInput={(e) => setEmail(e.currentTarget.value)}
  onChange={() => save(email)}
  required
  requiredText="مطلوب"
  error={submitted && !isValid(email)}
  errorText="أدخِل عنوان بريد إلكتروني كاملًا."
/>

<TextField label="الرسالة" multiline minRows={3} maxRows={8} value={message}
  onInput={(e) => setMessage(e.currentTarget.value)} />

// تاريخ: القيمة بصيغة ISO 8601، أو فارغة ما دام أحد المقاطع فارغًا.
<TextField
  label="تاريخ البدء"
  type="date"
  min="2026-01-01"
  value={start}
  invalidText="أكمِل التاريخ."
  unavailableText="اختر تاريخًا في 2026 أو بعدها."
  segmentEmptyText="فارغ"
  picker
  pickerLabel="اختيار تاريخ البدء"
  onChange={(e) => setStart(e.currentTarget.value)}
  onEntryError={(e) => report(e.detail.reason)}
  onPickerRequest={() => setPickerOpen(true)}
/>
```

**SwiftUI**

```swift
import Tanrei

TanreiTextField("البريد الإلكتروني", text: $email, type: .email,
                supportingText: "نستخدمه لتسجيل دخولك فقط.",
                errorText: "أدخِل عنوان بريد إلكتروني كاملًا.",
                error: submitted && !isValid(email),
                textContentType: "email", // اسم تعبئة تلقائية من HTML
                onCommit: save,
                // مرِّر الإجراء هنا: المُعدِّل .onSubmit المحيط يعمل قبل onCommit.
                onSubmit: signIn)

// تعدد الأسطر هو المحور العمودي مع مدى لحد الأسطر.
TanreiTextField("الرسالة", text: $message, axis: .vertical, lineLimit: 3...8)
```

**Compose**

```kotlin
import androidx.compose.foundation.text.KeyboardActions
import io.github.chnotchy.tanrei.components.TanreiTextField
import io.github.chnotchy.tanrei.components.TanreiTextFieldType

var email by remember { mutableStateOf("") }
TanreiTextField(
    value = email,
    onValueChange = { email = it },
    label = "البريد الإلكتروني",
    type = TanreiTextFieldType.Email,
    contentType = "email", // اسم تعبئة تلقائية من HTML
    supportingText = "نستخدمه لتسجيل دخولك فقط.",
    isError = submitted && !isValid(email),
    errorText = "أدخِل عنوان بريد إلكتروني كاملًا.",
    onCommit = { save(it) },
    keyboardActions = KeyboardActions(onDone = { signIn() }),
)

// singleLine هي عكس multiline التي في المواصفة.
TanreiTextField(value = message, onValueChange = { message = it }, label = "الرسالة", singleLine = false, minLines = 3)
```

**Flutter**

```dart
import 'package:tanrei/tanrei.dart';

TanreiTextField(
  controller: email, // أو initialValue: '…'
  labelText: 'البريد الإلكتروني',
  type: TanreiTextFieldType.email,
  autofillHints: TanreiTextField.autofillHintsFromHtml('email'),
  helperText: 'نستخدمه لتسجيل دخولك فقط.',
  isError: submitted && !isValid(email.text),
  errorText: 'أدخِل عنوان بريد إلكتروني كاملًا.',
  onCommit: save,
  onSubmitted: (String value) => signIn(),
);

TanreiTextField(labelText: 'الرسالة', multiline: true, minLines: 3);
```

**React Native**

```tsx
import { TextField } from '@tanrei/react-native';

<TextField
  label="البريد الإلكتروني"
  type="email"
  autoComplete="email"
  value={email}
  onChangeText={setEmail}
  supportingText="نستخدمه لتسجيل دخولك فقط."
  error={submitted && !isValid(email)}
  errorText="أدخِل عنوان بريد إلكتروني كاملًا."
  onEndEditing={save}
  onSubmitEditing={signIn}
/>
<TextField label="الرسالة" multiline minRows={3} value={message} onChangeText={setMessage} />
```

### مستوى واحد إلى الأسفل

الحقل نفسه مكتوبًا باليد من عضويه هو الصورة نفسها، ومربع النص (text box) نفسه عند التقنيات المساعدة، بالاسم والوصف والحالات نفسها:

```html
<tanrei-field label="البريد الإلكتروني" required required-text="مطلوب"
  supporting-text="نستخدمه لتسجيل دخولك فقط.">
  <tanrei-text-input name="email" type="email" autocomplete="email"></tanrei-text-input>
</tanrei-field>
```

انزل مستوى واحدًا حين تحتاج إلى ترتيب لا يقدّمه حقل النص:

| تحتاج إلى | استخدم |
| --- | --- |
| تسمية وصندوق ومساعدة وخطأ وعدد | حقل النص |
| شيء من عندك داخل الإطار، بجانب الصندوق أو تحته | [حقل](https://tanrei.chnotchy.com/ar/components/field/) بداخله [حقل إدخال النص](https://tanrei.chnotchy.com/ar/components/text-input/) وعنصرك أنت |
| الصندوق وحده، تحت تسمية تقف في مكان آخر: عامل تصفية في شريط أدوات، أو خلية في جدول، أو صف تسميته بجانبه | [حقل إدخال النص](https://tanrei.chnotchy.com/ar/components/text-input/) وحده، وتسمّيه `label` الخاصة به |

ما يتغيّر في المستوى الأدنى هو الموضع الذي يُقال فيه كل شيء. الخاصيتان `name` و `value` تكونان على حقل إدخال النص، وهو عندئذ عنصر التحكم الذي يلقاه النموذج، وأحداثه تُسمع عليه. أما `label` و `error` و `disabled` والمطلوب أو الاختياري فتبقى على الحقل، وهو يمرّرها إلى عنصر التحكم: فلا تعيّن ما يخص حقل الإدخال منها.

وشيء واحد يفعله حقل النص ولا يفعله الحقل وحقل إدخال النص المكتوبان باليد: يُبقي العدد مواكبًا. وباليد، مع تعيين `counter`، أعطِ الحقل عدد حقل الإدخال عند كل تغيّر:

```js
field.countText = input.countText;
input.addEventListener('input', () => (field.countText = input.countText));
```

## المواصفات

### ما يعطيه كل عضو

| الجانب | من الحقل | من حقل إدخال النص |
| --- | --- | --- |
| الخصائص | `label`، `labelHidden`، `supportingText`، `errorText`، `error`، `disabled`، `required`، `optional`، `requiredMark`، `requiredText`، `optionalText` | كل ما عداها: `variant`، `size`، `type`، `value`، `placeholder`، `readOnly`، والأسطر وتغيير الحجم، `wrap`، `maxLength`، `counter`، والبادئة واللاحقة، `autocomplete`، وكل ما يخص التاريخ أو الوقت |
| الأحداث | — | `input`، `change`، `action`، `pickerRequest`، `entryError` |
| المنافذ (slots) | `label-icon` | `leading-icon`، `trailing-icon` |
| رموز التصميم | `comp.field.*` | `comp.input-box.*` للصندوق، وهي التي يقرؤها كل صندوق إدخال؛ و `comp.text-input.*` لما يرسمه حقل إدخال النص وحده |

لحقل إدخال النص `label` و `labelHidden` و `error` و `disabled` خاصة به. وهي ليست ما يعيّنه حقل النص: فالخاصية `label` فيه هي تسمية الحقل، وهي تسمّي حقل الإدخال، وفي الحقل من الطراز filled أو outlined هي ما يعوم في الصندوق.

### رموز التصميم

ليس لحقل النص رمز تصميم خاص به. صندوقه يقرأ [رموز تصميم حقل إدخال النص](https://tanrei.chnotchy.com/ar/components/text-input/#%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B5%D9%81%D8%A7%D8%AA)، وصفوفه، أي التسمية والعلامة والمساعدة والخطأ والعدد، تقرأ [رموز تصميم الحقل](https://tanrei.chnotchy.com/ar/components/field/#%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B5%D9%81%D8%A7%D8%AA)، أينما عُيِّنت. والجدول أدناه يسرد رموز الحقل. ولتغيير مثيل واحد، عيِّن رمز تصميم العضو عليه:

```html
<tanrei-text-field label="البريد الإلكتروني"
  style="--tanrei-comp-field-label-gap: 12px"></tanrei-text-field>
```

- Category: Text inputs
- Level: composed
- Listing: default
- Built from: Field, Text input
- Page: https://tanrei.chnotchy.com/components/text-field/
- Spec: https://github.com/chnotchy/tanrei/blob/main/specs/text-field.spec.json

### Availability

| Design system | Has it | Notes |
| --- | --- | --- |
| Tanrei (`tanrei`) | Yes | Variants left out: `filled`, `outlined`. |
| Cupertino (Apple HIG-inspired) (`cupertino`) | Yes | — |
| M3 Expressive-like (Material 3 Expressive-inspired) (`m3-expressive-like`) | Yes | — |
| M3-like (Material 3-inspired) (`m3-like`) | Yes | — |

### Platforms

- Web: the element `<tanrei-text-field>`, registered by importing `@tanrei/web` (or only its own module, `@tanrei/web/components/text-field`).
- React: `TextField` from `@tanrei/react`.

| Platform | Name | Status |
| --- | --- | --- |
| Web | `tanrei-text-field` | lagging |
| SwiftUI | `TanreiTextField` | lagging |
| Jetpack Compose | `TanreiTextField` | lagging |
| Flutter | `TanreiTextField` | lagging |
| React Native | `TextField` | lagging |

Names a platform gives in its own idiom:

| Spec | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
| --- | --- | --- | --- | --- | --- |
| `value` (prop) | `value` | `text` | `value` | `controller` | `value` |
| `label` (prop) | `label` | `label` | `label` | `labelText` | `label` |
| `labelHidden` (prop) | `labelHidden` | `labelsHidden` | `labelHidden` | `labelHidden` | `labelHidden` |
| `placeholder` (prop) | `placeholder` | `prompt` | `placeholder` | `hintText` | `placeholder` |
| `supportingText` (prop) | `supportingText` | `supportingText` | `supportingText` | `helperText` | `supportingText` |
| `error` (prop) | `error` | `error` | `isError` | `isError` | `error` |
| `disabled` (prop) | `disabled` | `disabled` | `enabled` | `enabled` | `disabled` |
| `required` (prop) | `required` | `isRequired` | `required` | `required` | `required` |
| `optional` (prop) | `optional` | `isOptional` | `optional` | `optional` | `optional` |
| `multiline` (prop) | `multiline` | `axis` | `singleLine` | `multiline` | `multiline` |
| `minRows` (prop) | `minRows` | `lineLimit` | `minLines` | `minLines` | `minRows` |
| `maxRows` (prop) | `maxRows` | `lineLimit` | `maxLines` | `maxLines` | `maxRows` |
| `resizeLabel` (prop) | `resizeLabel` | `resizeLabel` | `resizeContentDescription` | `resizeSemanticLabel` | `resizeAccessibilityLabel` |
| `wrap` (prop) | `noWrap` | `wrap` | `softWrap` | `softWrap` | `wrap` |
| `counter` (prop) | `counter` | `counter` | `counter` | `showCounter` | `counter` |
| `counterText` (prop) | `counterText` | `counterText` | `counterText` | `counterSemanticText` | `counterAccessibilityText` |
| `counterNoLimitText` (prop) | `counterNoLimitText` | `counterNoLimitText` | `counterNoLimitText` | `counterNoLimitSemanticText` | `counterNoLimitAccessibilityText` |
| `prefixText` (prop) | `prefixText` | `prefix` | `prefix` | `prefixText` | `prefix` |
| `suffixText` (prop) | `suffixText` | `suffix` | `suffix` | `suffixText` | `suffix` |
| `autocomplete` (prop) | `autocomplete` | `textContentType` | `contentType` | `autofillHints` | `autoComplete` |
| `picker` (prop) | `picker` | `onPickerRequest` | `onPickerRequest` | `onPickerRequest` | `onPickerRequest` |
| `pickerLabel` (prop) | `pickerLabel` | `pickerLabel` | `pickerContentDescription` | `pickerSemanticLabel` | `pickerAccessibilityLabel` |
| `input` (event) | `input` | `text` | `onValueChange` | `onChanged` | `onChangeText` |
| `change` (event) | `change` | `onCommit` | `onCommit` | `onCommit` | `onEndEditing` |
| `action` (event) | `action` | `onSubmit` | `keyboardActions` | `onSubmitted` | `onSubmitEditing` |
| `pickerRequest` (event) | `pickerrequest` | `onPickerRequest` | `onPickerRequest` | `onPickerRequest` | `onPickerRequest` |
| `entryError` (event) | `entryerror` | `onEntryError` | `onEntryError` | `onEntryError` | `onEntryError` |
| `resizeEnd` (event) | `resizeend` | `onResizeEnd` | `onResizeEnd` | `onResizeEnd` | `onResizeEnd` |

Statuses: `planned` — In the inventory. Nothing shippable exists yet. `lagging` — An implementation of an earlier spec exists; it has not caught up with the current one. `alpha` — Implemented with tests. The API may still change. `beta` — Feature complete and at parity. Only fixes are expected. `stable` — Covered by semantic versioning. `deprecated` — Still shipped; scheduled for removal.

### Anatomy

- `field`: The Field: the label row with its glyph and its requirement mark, and the supporting row with the help, the error text and the count the text field gives it (TXF-67). In a look whose input floats the label it draws no label row.
- `text-input`: The text input, as the Field's one control: the box and everything typed in it, the icons, the prefix and the suffix, the segments of a date, the picker button, the resize handle, and the label that floats in the box in the looks that float one.

### Props

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `variant` | `enum`: `stacked`, `filled`, `outlined` | `"stacked"` | `variant` | Stacked is a filled box that shows focus and error with a line inside its edge and draws no label: the label of the Field that frames it stands above it. Filled and outlined float the label inside the box, marked by a tinted box and a bottom line, or by a border. Use one style per form. A design system may leave some out (the Tanrei system ships stacked only) or add values. (From Text input.) |
| `size` | `enum`: `small`, `medium`, `large` | `"medium"` | `size` | Minimum height of a single-line input's container: stacked 32 / 40 / 56, as tall as a Button of the same size, so that an input and a Button side by side in one row stand as tall as each other; filled and outlined 40 / 48 / 56, which hold the label that floats inside them. Medium and large are for forms; small is for an input in an app bar, a toolbar or a dense row of controls, beside a small select or button. The hit area always meets the minimum target. (From Text input.) |
| `type` | `enum`: `text`, `email`, `password`, `number`, `search`, `tel`, `url`, `code`, `date`, `time`, `date-time` | `"text"` | `type` | What the value is: chooses the keyboard, autocorrection, obscured entry and semantics. code is text written for a machine rather than for a reader — a snippet of configuration, a pattern, an identifier, a query, a key: a left-to-right run in the code face that the platform does not correct, capitalise, check for spelling or complete, on one line or, with multiline, on many. date, time and date-time are entered segment by segment in the locale's numeric form and held as ISO 8601. The value is a string for every type. (From Text input.) |
| `value` | `string` | `""` | `value` | The text in the field; for date, time and date-time, the ISO 8601 form of what its segments give (2026-09-27, 14:30, 2026-09-27T14:30), or empty while a segment is empty or the value is not available. (From Text input.) |
| `label` | `string` | `""` | `label` | Names the control, visibly and to assistive technology. Required, unless the control names itself (a checkbox or a switch with its own label): then leave it empty and the field adds only help and an error. (From Field: Names the text input. In a filled or outlined look the input draws it, floating in its box, and the Field draws no label row (FLD-25, TXI-13).) |
| `labelHidden` | `boolean` | `false` | `label-hidden` | Does not draw the label, which stays the accessible name. For a control whose visible label is elsewhere (a table column, a toolbar). (From Field: Hides the label wherever it would be drawn: the Field's row, or the input's floating label (FLD-25).) |
| `placeholder` | `string` | `""` | `placeholder` | A hint shown while the value is empty and the label is not in the input line (above, floated or hidden). Never a replacement for label. In a code field it is an example of the code and is drawn as code (TXI-53, TXI-54); a hint in words belongs in the supportingText of its Field. Ignored by a date, time or date-time field, whose empty segments each show their own. (From Text input.) |
| `supportingText` | `string` | `""` | `supporting-text` | Help shown below the control and given to assistive technology as the control's description. While the field is in error it gives way to errorText, unless the design system keeps both (comp.field.error-text.placement append). (From Field.) |
| `errorText` | `string` | `""` | `error-text` | Shown while error is true, in supportingText's place — or below it, which then stays, where the design system's comp.field.error-text.placement is append: what is wrong and how to put it right, in words. (From Field.) |
| `error` | `boolean` | `false` | `error` | Puts the field in the error condition: the error text is drawn, the control is exposed as invalid and, where it has an error condition of its own, drawn in it. What a value means is the product's to validate; the field never sets this itself. (From Field: The Field puts its text input in the input's own error condition (FLD-8, TXI-11).) |
| `disabled` | `boolean` | `false` | `disabled` | Disables the control and draws the frame as disabled. Disable a framed control here, not on the control, so that its label follows. (From Field: The Field disables its text input (FLD-14, TXI-5); the text field is then left out of its form (TXF-63).) |
| `readOnly` | `boolean` | `false` | `readonly` | The value can be focused, selected and copied, but not changed. (From Text input.) |
| `required` | `boolean` | `false` | `required` | What the form asks of the control: true exposes it as required and draws the required mark beside the label. It never validates: a missing answer is the product's to report with error. (From Field: The Field exposes its text input as required (FLD-10, TXI-23).) |
| `optional` | `boolean` | `false` | `optional` | Draws the optional tag after the label and adds optionalText to the control's description, because assistive technology has no state for it. Ignored while required is true: a control is never both. (From Field.) |
| `requiredMark` | `enum`: `auto`, `tag`, `asterisk`, `none` | `"auto"` | `required-mark` | How this control shows that it is required: tag is a small filled Tag with requiredText, asterisk is "*" after the label, none draws nothing and keeps the semantics. Auto takes comp.field.requirement.mark, which follows sys.behavior.requirement-mark, the system's one answer. Ignored unless required is true. (From Field.) |
| `requiredText` | `string` | `""` | `required-text` | The text of the required tag, in the product's language ("Required", "必須"). The product's: Tanrei has no word for it. Empty reads the product's words; with neither, FLD-24 says what is drawn. (From Field.) |
| `optionalText` | `string` | `""` | `optional-text` | The text of the optional tag, in the product's language ("Optional", "任意"); also read to assistive technology as part of the description. The product's: Tanrei has no word for it. Empty reads the product's words. (From Field.) |
| `multiline` | `boolean` | `false` | `multiline` | Accepts line breaks and shows several lines, sized as resize says. Ignored for password, date, time and date-time. (From Text input.) |
| `minRows` | `number` | `2` | `min-rows` | The fewest lines a multi-line field shows: the height of an empty auto-resized field, the starting and smallest height of a manually resized one, and the height of a fixed one. (From Text input.) |
| `maxRows` | `number` | `0` | `max-rows` | The most lines an auto-resized field grows to before it scrolls, and the tallest a manually resized one can be made; 0 is no limit. Ignored while resize is fixed. (From Text input.) |
| `resize` | `enum`: `auto`, `manual`, `fixed` | `"auto"` | `resize` | How a multi-line field gets its height. auto: it follows the number of lines between minRows and maxRows, with an animated change, and has no handle. manual: it starts at minRows lines and the person resizes it with the handle in its bottom end corner. fixed: it stays at minRows lines, with no handle. Ignored unless multiline. (From Text input.) |
| `resizeAxis` | `enum`: `vertical`, `both` | `"vertical"` | `resize-axis` | What the person can resize by hand: the height only, or the height and the width. Ignored unless resize is manual. (From Text input.) |
| `resizeLabel` | `string` | `""` | `resize-label` | The accessible name of the resize handle, in the product's language ("Resize"). The product's: Tanrei has no word for it. Empty reads the product's words. Required while the handle is shown. (From Text input.) |
| `wrap` | `boolean` | `true` | — | Whether a multi-line code field continues a line that does not fit on following rows (true), or keeps every line of the code on one row and scrolls sideways inside its container (false) — for code whose lines are read as rows: a table of values, a log, a file in which a line break means something. The value is the same either way. Ignored unless type is code and multiline is true: prose always wraps, and a single line always scrolls in its line. (From Text input.) |
| `maxLength` | `number` | `0` | `maxlength` | The most user-perceived characters the user can enter; 0 is no limit. Ignored for date, time and date-time. (From Text input.) |
| `counter` | `boolean` | `false` | `counter` | Keeps the character count (and maxLength, when set): part of the input's description and announced when typing pauses (TXI-19). The input draws none: a text field gives the count to its Field, which draws it at the end of its supporting row, and a product that frames the input by hand gives it to the Field's countText. (From Text input: The input keeps the count, the text field gives it to its Field, and the Field draws it (TXI-19, TXF-67, FLD-27).) |
| `counterText` | `string` | `""` | `counter-text` | The count said to assistive technology while counter is true and maxLength is greater than 0: the whole sentence in the product's language with three places the input fills — {count} with the characters entered, {limit} with maxLength and {remaining} with how many more can be entered ("{remaining} characters left", "{limit}文字中{count}文字"). Empty reads the product's words; with neither, the count is said as the digits it is drawn in ("12/40"). A sentence that is right for every number, or a prop set per count where the language needs another form for one. (From Text input.) |
| `counterNoLimitText` | `string` | `""` | `counter-no-limit-text` | The count said to assistive technology while counter is true and maxLength is 0: the whole sentence with one place, {count}, filled with the characters entered ("{count} characters", "{count}文字"). Empty reads the product's words; with neither, the count is said as its digits. (From Text input.) |
| `prefixText` | `string` | `""` | `prefix-text` | Fixed text before the value, not part of it. In a code field it is code: drawn in the code face at the left of the value in every layout direction (TXI-53). (From Text input.) |
| `suffixText` | `string` | `""` | `suffix-text` | Fixed text after the value, not part of it. In a code field it is code: drawn in the code face at the right of the value in every layout direction (TXI-53). (From Text input.) |
| `autocomplete` | `string` | `""` | `autocomplete` | The autofill hint, as an HTML autofill field name (email, current-password, new-password, one-time-code, tel, postal-code, …); each platform maps it to its own content type. A code field left without one asks the platform to offer no remembered entry (TXI-55). (From Text input.) |
| `locale` | `string` | `""` | `locale` | A BCP 47 language tag ("en-US", "ja-JP") for how a date, time or date-time field shows and reads its value: the order of the year, month and day segments, the separators, the clock, the digits and the names of the units. Empty uses the platform's current locale. The calendar is the Gregorian calendar in every locale. (From Text input.) |
| `min` | `string` | `""` | `min` | The earliest value a date, time or date-time field accepts from the person, in its ISO 8601 form; empty for no limit. (From Text input.) |
| `max` | `string` | `""` | `max` | The latest value a date, time or date-time field accepts from the person, in its ISO 8601 form; empty for no limit. (From Text input.) |
| `disabledDates` | `strings` | `` | `disabled-dates` | Dates inside min and max that a date or date-time field does not accept from the person, as ISO 8601 calendar dates — the same list the product gives its DateTimePicker. Ignored by a time field. (From Text input.) |
| `invalidText` | `string` | `""` | `invalid-text` | The words for a date, time or date-time input committed with some segments filled and others empty: given to the Field that frames it, which shows them as its error text (TXI-30). (From Text input: Shown by the Field, in its supporting row (FLD-28).) |
| `unavailableText` | `string` | `""` | `unavailable-text` | The words for a date, time or date-time input committed with a value before min, after max or, for a date, listed in disabledDates: given to the Field that frames it, which shows them as its error text (TXI-30). (From Text input: Shown by the Field, in its supporting row (FLD-28).) |
| `segmentEmptyText` | `string` | `""` | `segment-empty-text` | What assistive technology reads as the value of a date or time segment that holds nothing yet, in the product's language ("Empty"). The product's: Tanrei has no word for it. Empty reads the product's words; with neither, an empty segment has no value text. (From Text input.) |
| `picker` | `boolean` | `false` | `picker` | Shows the picker button in a date, time or date-time field. The field presents no picker itself: it emits pickerRequest, and the product presents a DateTimePicker in the matching mode and sets value to what was picked. (From Text input.) |
| `pickerLabel` | `string` | `""` | `picker-label` | The accessible name of the picker button ("Choose date"). Required while picker is shown. (From Text input.) |

### Events

| Event | Description |
| --- | --- |
| `input` | The user changed the value; carries the new value. Emitted for every change, not when the product sets value. A date, time or date-time field emits it when its value changes — when its last segment is filled, a filled field is edited, or it is emptied — not for a segment that leaves the value empty. (From Text input.) |
| `change` | The user committed a changed value (focus left the field, or the action key was pressed in a single-line field); carries the value. (From Text input.) |
| `action` | The user pressed the keyboard's action key (Enter, Return, Go, Search, Done) in a single-line field. (From Text input.) |
| `pickerRequest` | The user activated the picker button of a date, time or date-time field; carries the value, type, min and max. The product presents the picker and sets value to the picked value. (From Text input.) |
| `entryError` | The user committed a date, time or date-time field that is half-filled or whose value is not available; carries the reason (invalid: some segments are empty; unavailable: before min, after max or a listed date) and the text of the row of segments as drawn. The entry error itself is shown by the Field that frames the input (TXI-30). (From Text input.) |
| `resizeEnd` | The person finished changing the size of a field resized by hand: a drag of its handle ended, or a key or an activation of the handle changed the size (TXI-69). Carries lines, the number of lines the input shows, and width, the field's width in pixels WHILE resizeAxis is both (null otherwise). Not emitted when a change of resize, resizeAxis, minRows or maxRows gives the size back. (From Text input.) |

### Slots

| Slot | Description |
| --- | --- |
| `leading-icon` | An icon at the start of the input. (From Text input.) |
| `trailing-icon` | An icon at the end of the input, or the product's own icon-only Button (clear, reveal password). A date or time field's picker button comes after it. (From Text input.) |
| `label-icon` | A glyph before the label. (From Field.) |

### States

`enabled`, `disabled`, `hovered`, `focused`, `error`

### Accessibility

- Role: `textbox`
- Labeling: The text field adds nothing to what its members expose, and the one thing it coordinates — the drawn count (TXF-67) — is kept from assistive technology, which hears the count from the input: the Field gives the text input its name, its description and its required, invalid and disabled states (FLD-8, FLD-10, FLD-11, FLD-14), and the text input carries them on its own element (TXI-23). Assistive technology meets one text box — or, for a date or a time, one group of spin buttons — named by label, exactly as it meets a Field around a text input written by hand.
- Minimum target size: yes

| Keys | Action |
| --- | --- |
| Every key | The text input's (its accessibility block; TXI-3, TXI-41, TXI-43 to TXI-45, TXI-59). The text field handles no key and adds no focus stop (TXF-64). |

- One level down is the same thing: a Field with a text input in it. Every fixture has that pair as its twin, and the accessibility tree of the two is the same (TXF-62). What the pair by hand does not do by itself is keep the Field's count text equal to the input's count as the person types (TXF-67): the product writes it at each input.
- On the web the two members stand in the text field's own shadow root, so the form meets the text field and not the input (TXF-63); focus passes through to the input (TXF-64).

### Behaviour

Requirements in EARS form, each with its stable id.

- **TXF-62** THE text field SHALL be a Field that frames one text input, and nothing else. It SHALL give label, labelHidden, supportingText, errorText, error, disabled, required, optional, requiredMark, requiredText and optionalText to its Field and every other prop to its text input, each unchanged; SHALL hold the label-icon slot for its Field and the leading-icon and trailing-icon slots for its text input; and SHALL emit its text input's events as its own, each once. THE text field SHALL be as wide as the place it stands in, and its text input SHALL fill it: it is a block with no width of its own, as its Field is (FLD-1), around a control that fills the width it is given (TXI-63). It SHALL draw no part of its own, have no token of its own and hold no state of its own but the count it carries from one member to the other (TXF-67): what it shows, how it behaves and what it exposes to assistive technology SHALL be exactly what that Field and that text input do when a product places the one in the other (FLD-1 to FLD-28; TXI-1 to TXI-63), with the Field given the input's count — the label row and its requirement mark (FLD-2 to FLD-6), or the label that floats in the box with the Field's row left out (FLD-25, TXI-13, TXI-50); the supporting row, the error and the count (FLD-7 to FLD-9, FLD-26, FLD-27, TXI-19, TXF-67); the name, the description and the states (FLD-10, FLD-11, FLD-14, TXI-23); and a date's entry error shown in the Field's row (FLD-28, TXI-30).
- **TXF-63** WHERE the platform has forms (the web) THE text field SHALL be the one control the form sees: it SHALL take name, submit its text input's value, reset to the value it was first given, restore it on navigation, report to the form's constraint validation exactly what its text input would report there (TXI-23, TXI-30), and be left out WHILE disabled is true or a disabled group of the form holds it; its text input and its Field SHALL take no part in the form themselves. WHEN the action key asks for the form's submission (TXI-3) the form asked SHALL be the text field's own.
- **TXF-64** WHEN the text field is given focus — by the product, by a press on any part of it that FLD-12 or TXI-8 gives to the input, or by a form that reports its validity — THE text field SHALL pass the focus to its text input (in a date, time or date-time field, to the segment TXI-43 names) and SHALL add no stop to the focus order: the stops inside it are its text input's, in that input's order (an interactive slot element, the picker button, the resize handle). WHILE focus is anywhere inside it THE text field SHALL count as focused for its Field (FLD-13).
- **TXF-65** IF the text field is placed in a Field THE text field SHALL in debug builds report that it is a field already and that the bare control is the text input, and both SHALL still render (FLD-15). WHILE it stands in a field group THE text field SHALL follow that group's disabled, through its own Field, and take nothing else from the group (FGR-20).
- **TXF-66** THE text field SHALL have no words of its own and SHALL read none: requiredText and optionalText are read by its Field (FLD-24), resizeLabel and segmentEmptyText by its text input (TXI-52), each from the instance's prop and then from the product's words.
- **TXF-67** WHILE counter is true THE text field SHALL give its Field, as its count text (FLD-27), the count its text input keeps (TXI-19), as the input writes it, and SHALL give the new one in the same frame in which the value changes — by typing, by a paste, because the product set value or maxLength — without a motion and without an announcement of its own: the input describes and announces its count itself (TXI-19) and the Field keeps the drawn text from assistive technology (FLD-27). WHILE counter is false THE text field SHALL give its Field no count text. THE text field SHALL NOT count, format or write a digit itself.
- **TXF-68** WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE text field SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on the element that carries its role — an id reference by the elements it names in the host's tree or a tree around it, an error message as part of the description while the text field is invalid — except those the text field owns (aria-label, aria-labelledby, aria-disabled), which it SHALL move and not expose: its name is label (TXF-62). WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE text field SHALL take it off that element. WHEN the product sets an aria- attribute the text field owns THE text field SHALL report it in debug builds.

### Tokens

As written in the token documents (DTCG): an alias in braces names the token it takes its value from, which each design system resolves. On the web each token is a CSS custom property: `--tanrei` and the name after `tanrei`, joined by hyphens (`tanrei.comp.field.…` → `--tanrei-comp-field-…`).

#### `tanrei.comp.field`

| Token | Type | Value |
| --- | --- | --- |
| `comp.field.label.typescale` | `typography` | `{tanrei.sys.typescale.label}` |
| `comp.field.label.gap` | `dimension` | `{tanrei.sys.space.space100}` |
| `comp.field.label-icon.size` | `dimension` | `{tanrei.sys.icon.small}` |
| `comp.field.label-icon.gap` | `dimension` | `{tanrei.sys.space.space100}` |
| `comp.field.requirement.mark` | `number` | `{tanrei.sys.behavior.requirement-mark}` |
| `comp.field.requirement.gap` | `dimension` | `{tanrei.sys.space.space100}` |
| `comp.field.requirement.asterisk-gap` | `dimension` | `{tanrei.sys.space.space25}` |
| `comp.field.supporting-text.typescale` | `typography` | `{tanrei.sys.typescale.label-small}` |
| `comp.field.supporting-text.gap` | `dimension` | `{tanrei.sys.space.space50}` |
| `comp.field.counter.gap` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.field.motion.state-duration` | `duration` | `{tanrei.sys.motion.role.state.default}` |
| `comp.field.motion.state-easing` | `cubicBezier` | `{tanrei.sys.motion.easing.state}` |
| `comp.field.standard.label.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.field.standard.label-icon.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.supporting-text.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.counter.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.required-asterisk.color` | `color` | `{tanrei.sys.color.primary}` |
| `comp.field.standard.error.label.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.field.standard.error.label-icon.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.error.supporting-text.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.error.counter.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.error.required-asterisk.color` | `color` | `{tanrei.sys.color.primary}` |
| `comp.field.standard.error.value-text.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.value-text.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.field.standard.error-text.color` | `color` | `{tanrei.sys.color.error}` |
| `comp.field.value-text.typescale` | `typography` | `{tanrei.sys.typescale.label}` |
| `comp.field.value-text.gap` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.field.error-text.gap` | `dimension` | `{tanrei.sys.space.space50}` |
| `comp.field.error-text.placement` | `number` | `0` |

Per-state tokens, valued by the design system's pattern rules (not written by hand):

- `comp.field.<variant>.<state>.<property>` for the variants `standard`, the states `focused`, `disabled` and the properties `label.color`, `label-icon.color`, `supporting-text.color`, `required-asterisk.color`, `error.label.color`, `error.label-icon.color`, `error.supporting-text.color`, `error.required-asterisk.color`, `counter.color`, `error.counter.color`, `value-text.color`, `error.value-text.color`, `error-text.color`.

### ما يرسمه الويب بطريقة مختلفة

- جذر الظل (shadow root) في العنصر فيه عنصر `<tanrei-field>` بداخله عنصر `<tanrei-text-input>`، ولا شيء غيرهما. واستيراد العنصر يعرّف الاثنين.
- العنصر كتلة تملأ مكانها، لا صندوق مضمَّن في السطر بعرض حقل الإدخال النصي الخاص بالمتصفح.
- العنصر مرتبط بالنماذج (form-associated). يأخذ `name` و `form`، ويرسل القيمة، ولا يرسل شيئًا وهو معطَّل، ويعود عند إعادة الضبط إلى قيمة خاصية HTML (attribute) `value`، ويُستعاد عند التنقل، ويتبع عنصر `<fieldset>` المعطَّل، ويبلّغ بأن القيمة ناقصة ما دامت `required` معيَّنة وهو فارغ. وعضواه لا يضيفان أي مُدخلة (entry) إلى النموذج. والمفتاح Enter في حقل من سطر واحد يضغط الزر الافتراضي في نموذج العنصر؛ ألغِ الحدث `action` لتمنع ذلك.
- الأحداث `input` و `change` و `action` و `pickerrequest` و `entryerror` هي أحداث حقل إدخال النص نفسه. وهدفها هو العنصر، و `event.target.value` هي القيمة الجديدة في كل مستمع. وأنواع التفاصيل (detail) هي أنواع حقل الإدخال: `TanreiTextInputActionDetail` و `TanreiTextInputPickerRequestDetail` و `TanreiTextInputEntryErrorDetail`.
- الأجزاء: `field` و `text-input` هما العضوان. وأجزاؤهما لها هنا الأسماء نفسها التي لها في المستوى الأدنى: `label-icon`، `supporting-text`، `counter`؛ `container`، `outline`، `active-indicator`، `input`، `segment`، `prefix`، `suffix`، `leading-icon`، `trailing-icon`، `picker-button`، `resize-handle`. والجزءان `label` و `requirement-label` هما المرسومان، أيًّا كان العضو الذي يرسمهما؛ أما `field-label` و `text-input-label` و `field-requirement-label` و `text-input-requirement-label` فتسمّي ما يخص عضوًا واحدًا.
- العنصر نفسه غير قابل للتركيز وليس له دور: فالدالة `focus()` تذهب إلى حقل الإدخال. والضغط على صف التسمية أو على الصندوق أو على تسمية عائمة ينقل التركيز إلى حقل الإدخال. والضغط على المساعدة أو نص الخطأ أو العدد أو الفجوة بين صف والصندوق لا يفعل شيئًا.
- سمِّه بالخاصية `label`، ومعها `label-hidden` حيث لا يُراد رسم التسمية، ولا تسمِّه أبدًا بالخاصية `aria-label`، فهي لا تسمّي شيئًا هنا.
- خصائص HTML هي خصائص العضوين نفسها: بصيغة kebab-case، مثل `supporting-text` و `error-text` و `min-rows` و `no-wrap`، ما عدا `readonly` و `maxlength` و `autocomplete` و `min` و `max`. ولا توجد خاصية HTML اسمها `required`: اكتب `required`.
- قبل أن يُعرَّف العنصر لا يكون له حجم. احجز ارتفاعه.

## الإرشادات

### متى يُستخدم

استخدم حقل النص حين يكتب الأشخاص قيمة: اسمًا، عنوان بريد إلكتروني، بحثًا، رسالة. وحين ينتقون من مجموعة قيم معروفة، استخدم عنصر تحكم صُنع للاختيار. وحيث لا يُراد إلا الصندوق، لأن التسمية تقف في مكان آخر، كعامل تصفية في شريط أدوات أو خلية في جدول، استخدم [حقل إدخال النص](https://tanrei.chnotchy.com/ar/components/text-input/).

### اختيار الطراز والحجم

استخدم طرازًا واحدًا في النموذج كله.

| الطراز | يميّزه | أين |
| --- | --- | --- |
| الطراز Stacked، وهو الافتراضي | التسمية فوق صندوق ملوَّن تلوينًا خفيفًا بلا حافة. التركيز يرسم خطًّا داخل حافة الصندوق، فلا يحرّك شيئًا؛ والخطأ يرسم خطًّا رفيعًا في حالة السكون. | كل نظام. وهو الطراز الوحيد الذي يقدّمه نظام Tanrei. |
| الطراز Filled | صندوق ملوَّن تلوينًا خفيفًا وخط سفلي، والتسمية تعوم داخله | إعدادات Material الجاهزة والإعداد الجاهز cupertino |
| الطراز Outlined | حدّ يثخن عند التركيز، والتسمية تعوم إليه | إعدادات Material الجاهزة والإعداد الجاهز cupertino |

الافتراضي هو stacked في كل نظام، ومنها الإعدادات الجاهزة. والمنتج المبني على Material الذي يريد تسمية Material العائمة يعيّن `variant` في حقوله بالقيمة `outlined` أو `filled`. وتحت نظام Tanrei ما زال الطرازان `filled` و `outlined` يعملان، مع تحذير في أثناء التطوير.

الحجم `medium` (40) هو الحقل المكثَّف، والحجم `large` (56) هو الحقل القياسي. استخدم `medium` في عوامل التصفية والإعدادات الكثيفة، و `large` في نماذج تسجيل الدخول وإتمام الشراء. والحجم `small` (32) هو ارتفاع قائمة الاختيار الصغيرة، لحقل في شريط تطبيق أو شريط أدوات أو صف كثيف من عناصر التحكم، ونص الإدخال فيه 14. ونص الإدخال 16 في الحجمين الآخرين في النظام الافتراضي. والارتفاعات حدود دنيا: يكبر الحقل مع النص الأكبر، ومنطقة اللمس تبلغ الحد الأدنى للهدف دائمًا.

### التسميات والنصوص النائبة

- كل حقل يحتاج إلى الخاصية `label`. في الحقل من الطراز stacked تقف فوق الصندوق، من حافة بدايته، ولا تتحرك ولا يتغيّر حجمها أبدًا؛ والتسمية الطويلة تلتفّ ولا تُقطع. ويستطيع المنفذ `label-icon` أن يضع رسم أيقونة (glyph) قبلها. وفي الحقل من الطراز filled أو outlined تستقر التسمية داخل الحقل ما دام فارغًا، وتعوم حين يكون عليه التركيز أو فيه قيمة.
- الخاصية `labelHidden` توقف رسم التسمية، لكنها تبقى الاسم المتاح للتقنيات المساعدة، وتبقى المساعدة والخطأ تحت الصندوق. وحيث لا يُراد إلا الصندوق، كعامل تصفية في شريط أدوات، أو خلية، أو صف تقف تسميته بجانبه، استخدم بدلًا منها [حقل إدخال النص](https://tanrei.chnotchy.com/ar/components/text-input/) بالخاصية `label` الخاصة به.
- النص النائب تلميح، كقيمة نموذجية. يظهر ما دام الحقل فارغًا والتسمية ليست في سطر الإدخال: دائمًا في الحقل من الطراز stacked، وفي الطرازين الآخرين فقط ما دامت التسمية عائمة أو مخفيّة. وليس هو الاسم أبدًا.

### مطلوب واختياري

الخاصيتان `required` و `optional` تقولان ما يطلبه النموذج من الحقل: `required` أن الجواب لازم، و `optional` أنه يجوز تركه فارغًا. والحقل لا يكون الاثنين معًا أبدًا: فإن عُيِّنتا كلتاهما كان مطلوبًا.

- **المطلوب** يعرض الحقل على أنه مطلوب ويرسم علامة المطلوب بجانب التسمية.
- **الاختياري** يرسم وسم الاختياري ويضيف نصه إلى وصف الحقل.
- **العلامة** وسم صغير بعد التسمية في الطراز stacked افتراضيًّا: من الطراز filled للمطلوب، ومن الطراز tonal للاختياري. كلماتها هي `requiredText` و `optionalText`، وهي كلماتك: على الحقل، أو مرة واحدة للمنتج كله بالدالة `setWords()`. لا يتضمن Tanrei أي كلمة: من دون `requiredText` تقف نجمة في مكان الوسم، ومن دون `optionalText` لا يُرسم وسم. وهي لا تزيد صف التسمية ارتفاعًا، وتلتفّ إلى سطر خاص بها حين لا تترك لها التسمية مكانًا.
- **نجمة بدلًا منها.** أيّ علامة يرسمها الحقل المطلوب اختيار واحد يختاره نظام التصميم لكل النماذج بالرمز `sys.behavior.requirement-mark`: الوسم في النظام الافتراضي، ونجمة في إعدادات Material الجاهزة، ولا شيء في cupertino. والخاصية `requiredMark` تتجاوزه لحقل واحد (`tag` أو `asterisk` أو `none`، والأخيرة تُبقي الدلالات ولا ترسم شيئًا). والحقل من الطراز filled أو outlined يرسم النجمة حيث يُطلب الوسم.
- **الاختياري في تسمية عائمة.** الحقل من الطراز filled أو outlined لا مكان فيه لوسم الاختياري بجانب تسمية تعوم: فيرسم `optionalText` بعد التسمية بدلًا منه، كلمةً («الشركة اختياري»، «会社名 （任意）»)، ساكنة وعائمة معها. اكتب الكلمة كما تعرضها نماذجك، بأقواس أو من دونها.
- **لا تتحقق من شيء.** الحقل لا يعيّن `error` أبدًا لقيمة ناقصة. أنت تفعل ذلك، بالخاصيتين `error` و `errorText`.

علِّم الأقل من النوعين في النموذج: حيث تكون أكثر الحقول مطلوبة علِّم الاختيارية، والعكس بالعكس. وإن استخدمت النجمة — والحقل من الطراز filled أو outlined يستخدمها دائمًا للحقل المطلوب — فقل مرة واحدة في النموذج، قرب أعلاه، ما معناها («\* مطلوب»): فالنجمة عُرف لا كلمة، وليس كل أحد يعرفه.

والحقل المطلوب يعرض علامة: عيِّن `requiredMark` بالقيمة `none` حيث لا تريدها.

### نص المساعدة ونص الخطأ

- الخاصية `supportingText` سطر واحد من المساعدة تحت الحقل. ويُقرأ أيضًا وصفًا للحقل.
- التحقق من شأنك. حين تكون القيمة خاطئة عيِّن `error` واكتب `errorText`: فهو يأخذ مكان النص المساعد ما دام الحقل في حالة الخطأ، فلا يزيد ارتفاع النموذج في حالة الخطأ عنه في الراحة. قل فيه ما قالته المساعدة حيث يظل مهمًّا. ونظام التصميم الذي يُبقي المساعدة ظاهرة يعيّن `comp.field.error-text.placement` بالقيمة `append`: فيُرسم نص الخطأ عندئذ تحت المساعدة، ويزيد ارتفاع الحقل سطرًا ما دام في حالة الخطأ (انظر [الحقل](https://tanrei.chnotchy.com/ar/components/field/#%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B9%D8%AF%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1)).
- قل كيف تُصحَّح القيمة، لا أنها خاطئة فحسب: «أدخِل عنوان بريد إلكتروني كاملًا.»، لا «غير صالح».
- اعرض الخطأ بعد أن يغادر الشخص الحقل أو يرسل النموذج، لا وهو ما زال يكتب.

### العدّاد

- الخاصية `maxLength` تحدّ ما يستطيع الشخص كتابته. وهي تعدّ الأحرف كما يراها الناس، فالإيموجي أو الحرف ذو العلامة يُعدّ مرة واحدة. واللصق يُقصَّر ليناسب الحد. أما القيمة التي تعيّنها أنت فلا تُقصَّر أبدًا.
- الخاصية `counter` تعرض العدد في نهاية صف النص المساعد، يتبعه الحد حين تكون `maxLength` معيَّنة («12/40»).
- اعرض العدّاد فقط حين يهمّ الحدُّ الشخصَ، كما في اسم معروض أو نبذة قصيرة.

### أنواع الإدخال

الخاصية `type` تختار لوحة المفاتيح والتصحيح التلقائي والإدخال المحجوب. والقيمة سلسلة نصية في كل الأنواع.

| النوع | لوحة المفاتيح والسلوك |
| --- | --- |
| `text` | لوحة مفاتيح عامة. |
| `email` | لوحة مفاتيح للبريد الإلكتروني، بلا تكبير تلقائي للأحرف ولا تصحيح تلقائي. |
| `password` | إدخال محجوب وآمن، بلا تصحيح تلقائي. سطر واحد دائمًا. |
| `number` | لوحة مفاتيح رقمية فيها فاصلة عشرية. القيمة لا تُحلَّل ولا تُقرَّب ولا يُتحقق منها. |
| `search` | لوحة مفاتيح عامة يُقرأ مفتاح الإجراء فيها «بحث». |
| `tel` | لوحة أرقام الهاتف. |
| `url` | لوحة مفاتيح لعناوين URL، بلا تكبير تلقائي للأحرف ولا تصحيح تلقائي. |
| `code` | لوحة مفاتيح عامة، ولا يُفعل بالنص شيء: بلا تصحيح تلقائي ولا تكبير تلقائي للأحرف ولا تدقيق إملائي ولا استبدال أحرف. سطر واحد، أو عدة أسطر مع `multiline`. انظر [الشيفرة](https://tanrei.chnotchy.com/ar/components/text-field/#%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A9). |
| `date` و `time` و `date-time` | تاريخ أو وقت أو كلاهما، يُدخل وحدةً وحدةً بالصيغة الرقمية للإعدادات المحلية. سطر واحد دائمًا. انظر [التواريخ والأوقات](https://tanrei.chnotchy.com/ar/components/text-field/#%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B1%D9%8A%D8%AE-%D9%88%D8%A7%D9%84%D8%A3%D9%88%D9%82%D8%A7%D8%AA). |

أضِف `autocomplete` باسم تعبئة تلقائية من HTML (`email` و `current-password` و `one-time-code` …) لتستطيع المنصة ملء الحقل. وكل منصة تقابله بنوع المحتوى الخاص بها. أما الرمز القصير المعروف الطول الذي يُرسم في خانات فله [حقل إدخال الرمز لمرة واحدة](https://tanrei.chnotchy.com/ar/components/one-time-code-input/).

### عدة أسطر

الخاصية `multiline` تقبل فواصل الأسطر وتعرض عدة أسطر. والخاصية `resize` تقول كيف يأخذ الحقل ارتفاعه:

| `resize` | الارتفاع | المقبض | `minRows` و `maxRows` |
| --- | --- | --- | --- |
| `auto` (الافتراضي) | يتبع عدد الأسطر، بحركة قصيرة | لا شيء | أقل عدد من الأسطر وأكثره. وبعد الأكثر يُمرَّر؛ والقيمة 0 تعني بلا حد |
| `manual` | ما يعطيه إياه الشخص. يبدأ عند `minRows` | في الزاوية السفلى عند حافة النهاية | أصغر ما يمكن أن يُجعل عليه وأطوله |
| `fixed` | `minRows` من الأسطر | لا شيء | تُتجاهل `maxRows` |

- **الوضع Auto** يناسب أكثر الحقول: تعليق، رسالة، وصف. عيِّن `maxRows` حيث يجب ألا يدفع نص طويل بقية النموذج بعيدًا.
- **الوضع Manual** يناسب نصًّا يعيد الشخص قراءته ويرتّبه: ملاحظات، وصف طويل، شيفرة. الخاصية `resizeAxis` قيمتها `vertical` افتراضيًّا؛ والقيمة `both` تتيح للشخص أيضًا أن يغيّر عرض الحقل، ضمن ما يسمح به تخطيطه. ويُحفظ الحجم، والنص يلتفّ ويُمرَّر داخله.
- **الوضع Fixed** يناسب نموذجًا يجب ألا يتحرك تخطيطه، ككتلة العنوان البريدي.
- **المقبض يعمل بلا سحب.** هو [مقبض تغيير حجم](https://tanrei.chnotchy.com/ar/components/handle/) بالحجم `small` في الزاوية السفلى عند حافة النهاية، لا يظهر حتى يمرّ المؤشر فوق الحقل أو يأخذ الحقل التركيز، وهو موضع توقف للتركيز تسمّيه الخاصية `resizeLabel`. مفاتيح الأسهم تغيّر الحجم بسطر، والمفتاحان Page Up و Page Down بعدد `minRows` من الأسطر، والمفتاحان Home و End يذهبان إلى الأصغر والأطول، والنقرة أو المفتاح Enter أو Space تلائم الارتفاع مع النص، أو تعيده إلى `minRows` حين يكون ملائمًا سلفًا. وحيث تكون `resizeAxis` بالقيمة `both`، تجعل النقرة نفسها الحقل بعرض مكانه، وتعيد النقرة التالية العرض الذي كان له، فيستطيع المؤشر تغيير العرض بلا سحب. وهدفه هو الحد الأدنى للهدف، مع أن خطه صغير. وحين يغيّر الشخص الحجم، يصدر الحقل `resizeend` مع عدد الأسطر التي يعرضها (ومع عرضه، حيث يتغيّر حجمه في الاتجاهين)، فتستطيع أن تحتفظ بالحجم الذي اختاره. والحقل المعطَّل لا مقبض له؛ والحقل الذي للقراءة فقط يحتفظ به، لأن القراءة قد تحتاج إلى المساحة.
- **لا شيء فوق النص يتحرك.** السطر الأول في الحقل المتعدد الأسطر يقف حيث يرسم الحقل ذو السطر الواحد سطره، وأيقوناته وبادئته ولاحقته موسَّطة على ذلك السطر. وكل سطر آخر يقع تحته، فتبقى التسمية والسطر الأول في مكانهما والارتفاع يتغيّر.

### الشيفرة

الحقل من النوع `code` (`type="code"`) لنص كُتب لآلة لا لقارئ: نمط، أو معرّف، أو مفتاح، أو استعلام، أو مقتطف من JSON أو YAML. وهو الحقل نفسه، بالتسمية والمساعدة والخطأ والعدّاد والأحجام وسلوك النموذج نفسها، وسطر إدخاله يحفظ الشيفرة كما كُتبت تمامًا.

- **من اليسار إلى اليمين، في كل لغة.** القيمة ومؤشر الكتابة فيها والنص النائب والبادئة واللاحقة صف واحد من اليسار إلى اليمين يبدأ من اليسار، حتى في صفحة من اليمين إلى اليسار، وأيًّا كان الحرف الأول في الشيفرة: فالحقل الفارغ، والحقل الذي ليس فيه إلا `{`، والحقل الذي أول سلسلة نصية فيه عربية، تُخطَّط كلها بالطريقة نفسها. وكل ما عدا ذلك يتبع الصفحة: التسمية والأيقونات ونص المساعدة أو نص الخطأ والعدّاد ومقبض تغيير الحجم. والسلسلة النصية أو التعليق المكتوب بنظام كتابة من اليمين إلى اليسار يُخطَّط داخل سطره، ولا يغيّر ترتيب شيء مما حوله.
- **خط الشيفرة، بمقاس نص الإدخال.** عائلة الخط هي التي لدور الشيفرة؛ أما المقاس وارتفاع السطر فيبقيان ما لنص الإدخال، فيكون حقل الشيفرة بارتفاع حقل النص الذي بجانبه. وتُحفظ كل مسافة، وحرف الجدولة (tab) يصل إلى موضع الجدولة التالي، ولا يُدمج حرفان في حرف مركَّب (ligature). ولا يُلوَّن شيء بحسب معناه.
- **تُترك كما هي.** يُطلب من المنصة ألا تصحّح القيمة ولا تكبّر أحرفها ولا تدقّقها إملائيًّا ولا تترجمها ولا تكملها، وألا تحوّل علامات الاقتباس المستقيمة إلى معقوفة. واللصق نص عادي، حرفًا بحرف. والقيمة لا تُحذف المسافات من طرفيها ولا تُحلَّل ولا يُتحقق منها أبدًا: فالقول بسلامة صياغتها من شأنك، بالخاصيتين `error` و `errorText`.
- **سطر واحد أو عدة أسطر.** السطر الواحد يناسب نمطًا أو مفتاحًا. ومع `multiline` يكمل السطر الذي لا يتسع له العرض في الصفوف التالية افتراضيًّا؛ ولا تحمل القيمة من فواصل الأسطر إلا ما في الشيفرة.
- **أسطر لا تلتفّ.** الخاصية `wrap` بالقيمة false، وهي `no-wrap` على الويب، تُبقي كل سطر من الشيفرة في سطر واحد من الحقل، لجدول قيم، أو سجل أحداث (log)، أو ملف لفاصل السطر فيه معنى. والسطر الطويل يُمرَّر جانبيًّا داخل الحقل ولا يوسّع شيئًا. ولا يقرأ `wrap` إلا حقل شيفرة متعدد الأسطر: فالنص المتصل يلتفّ دائمًا، والسطر الواحد يُمرَّر دائمًا في سطره.
- **المفتاح Tab ينقل التركيز.** لا يتغيّر معنى أي مفتاح: المفتاح Tab لا يضيف مسافة بادئة أبدًا، والمفتاح Enter لا يضيف مسافة بادئة، ولا يُغلق قوس بالنيابة عنك. وحرف الجدولة يصل باللصق أو من منتجك، ويُحفظ.
- **ليس محرّرًا.** لا ألوان للصيغة، ولا أرقام أسطر، ولا طيّ، ولا علامات خطأ بحسب السطر. للشيفرة التي تُعرض ولا تُكتب استخدم [كتلة الشيفرة](https://tanrei.chnotchy.com/ar/components/code-block/)؛ وللمحرّر ضمِّن المحرّر الذي اختاره منتجك.
- **النص النائب مثال من الشيفرة**، يُرسم شيفرةً. أما التلميح بالكلمات فمكانه `supportingText`، وفيه أيضًا يقول الحقل ما ينتظره («JSON»).

في حقل من اليمين إلى اليسار تبدأ قيمة الشيفرة من اليسار، أما قيمة النوع `email` أو `url` أو `tel` أو `number` أو `password` فتُكتب من اليسار إلى اليمين عند حافة البداية للحقل، أي اليمين. والمنصات الأخرى لم تبنِ النوع code بعد.

### التواريخ والأوقات

الحقل من النوع `date` أو `time` أو `date-time` صف من المقاطع في سطر الإدخال، مقطع لكل وحدة: الشهر واليوم والسنة، والساعة والدقيقة، وفي نظام 12 ساعة فترة اليوم. تقف بترتيب الإعدادات المحلية وبفواصلها. ويحفظ الحقل القيمة بصيغة ISO 8601، بلا منطقة زمنية.

| النوع | القيمة | الصف في en-US | الصف في ja-JP |
| --- | --- | --- | --- |
| `date` | `2026-09-27` | `09/27/2026` | `2026/09/27` |
| `time` | `14:30` | `2:30 PM` | `14:30` |
| `date-time` | `2026-09-27T14:30` | `09/27/2026, 2:30 PM` | `2026/09/27 14:30` |

- **الإعدادات المحلية.** الخاصية `locale`، أو إعدادات المنصة، تعيّن الترتيب والفواصل ونظام الساعة والأرقام. والمقطع الفارغ يعرض نصه النائب (`mm`، `dd`، `yyyy`)، فيعرض الصف صيغته دائمًا. وكل مقطع بعرض الأعرض من نصه النائب وأعرض قيمه، فلا يتحرك الصف وأنت تكتب أو تمحو. وهذه الأنواع تتجاهل `placeholder` و `prefixText` و `suffixText` و `maxLength` و `multiline`.
- **التنقل.** المفتاح Tab يزور كل مقطع، ثم زر المنتقي. ومفتاحا السهمين الأيسر والأيمن ينقلان إلى المقطع الذي في تلك الجهة، في كل اتجاه للتخطيط: فالصف مكتوب من اليسار إلى اليمين، كما يُكتب التاريخ بالأرقام. والضغط على مقطع ينقل التركيز إليه. والمقطع الذي عليه التركيز يُرسم نصًّا محدَّدًا، بلا مؤشر كتابة (caret).
- **التدرّج.** مفتاحا السهمين العلوي والسفلي يغيّران المقطع بواحد ويدوران عند الطرفين؛ وعلى مقطع فارغ يبدآن من تاريخ اليوم أو الوقت الحالي. والمفتاحان Page Up و Page Down يخطوان أبعد، والمفتاحان Home و End يذهبان إلى طرفي المدى.
- **الكتابة.** الرقم يملأ المقطع، وينتقل التركيز إلى التالي حين لا يمكن أن يمدّه رقم آخر، أو حين يُكتب الفاصل. والمفتاح Backspace يزيل رقمًا، وعلى مقطع فارغ يرجع إلى الوراء. والسنة تحتاج إلى أربعة أرقام. والتاريخ الذي لا وجود له لا يمكن إدخاله: اليوم الذي يتجاوز نهاية شهر اختير للتو يصير آخر يوم في ذلك الشهر.
- **اللصق.** تاريخ كامل أو وقت كامل يُلصق على أي مقطع يملأ الصف. يُقرأ على أنه ثلاث مجموعات من الأرقام بترتيب الإعدادات المحلية، والمجموعة الأولى ذات الأرقام الأربعة تُقرأ على أنها السنة، فيعمل تاريخ ISO الملصوق في كل مكان. والنسخ والقص يأخذان الصف كله.
- **القيمة** فارغة إلى أن يُملأ كل مقطع وتكون النتيجة متاحة. يصدر الحدث `input` حين تتغيّر القيمة، أي حين يُملأ المقطع الأخير أو يُعدَّل صف مملوء أو يُفرَّغ، ولا يصدر لمقطع يترك القيمة فارغة. ويصدر الحدث `change` حين يغادر التركيز مقاطع الحقل وزر المنتقي، أو حين يُضغط مفتاح الإجراء، والقيمة قد تغيّرت. والتنقل بين المقاطع لا يعتمد شيئًا.
- **خطأ الإدخال.** الحقل الذي يُترك نصف مملوء يعرض `invalidText`. والحقل الذي يُترك بقيمة قبل `min` أو بعد `max` أو مدرجة في `disabledDates` يعرض `unavailableText`. وكلاهما يُرسم خطأً ويصدر `entryError` مع سببه (`invalid` أو `unavailable`)؛ والتعديل التالي ينهيه. وهو الخطأ الوحيد الذي يعيّنه الحقل بنفسه، ولا يمسّ الخاصية `error` التي لك.
- **ما تعيّنه أنت** يُعرض كما هو، ولا يُتحقق منه أبدًا، ولا يصدر شيئًا.

نظام الساعة في الحقل هو نظام إعداداته المحلية: ليس فيه إعداد لنظام 12 أو 24 ساعة ولا درجة للدقائق، كما في DateTimePicker.

**زر المنتقي.** مع `picker` يرسم الحقل في نهايته زرًّا بأيقونة فقط، `calendar_month` للتاريخ و `schedule` للوقت، تسمّيه الخاصية `pickerLabel`. تفعيله يصدر `pickerRequest` مع القيمة والنوع و `min` و `max`؛ والصف النصف مملوء يرسل قيمة فارغة ولا يثير خطأ إدخال، لأن المنتقي يوشك أن يعطي قيمة كاملة. والحقل لا يعرض شيئًا بنفسه: منتجك يفتح [DateTimePicker](https://tanrei.chnotchy.com/ar/components/date-time-picker/) في الوضع المطابق، مرتكزًا على الحقل حين يكون مُرسى (docked)، ويعيّن الخاصية `value` في الحقل من الحدث `change` في المنتقي. أعطِ المنتقي قيم `min` و `max` و `disabledDates` نفسها التي للحقل. ويعود التركيز إلى الزر حين يُغلق المنتقي. والزر يتعطّل مع الحقل ولا يُرسم ما دام الحقل للقراءة فقط.

### افعل

- ضع النص الثابت الذي ليس جزءًا من القيمة في `prefixText` و `suffixText`: علامة عملة، وحدة.
- ضع إجراء المسح أو إجراء إظهار كلمة المرور في منفذ النهاية زرًّا بأيقونة فقط من عندك، له اسمه. زر المنتقي هو الإجراء الوحيد المبني في الحقل، ويأتي بعد إجراءاتك.
- استخدم `multiline` للنص الذي قد يمتد إلى عدة أسطر. وهو افتراضيًّا يكبر من `minRows` إلى `maxRows`، ثم يُمرَّر.
- عيِّن `required` على الحقول التي يطلبها النموذج، وقل مع ذلك ما الناقص في `errorText` حين يُرسل النموذج.
- استخدم `type="code"` لقيمة تقرؤها آلة، كنمط أو مفتاح أو مقتطف من إعدادات، وقل ما يجب أن تكون عليه في التسمية وفي `supportingText`.

### لا تفعل

- لا تستخدم النص النائب تسميةً. فهو يختفي ما إن يكتب أحد.
- لا تستخدم `number` لقيم ليست كميات، كرقم بطاقة أو رمز بريدي. استخدم `text` مع قيمة `autocomplete` المناسبة.
- لا تخلط الطُرُز في نموذج واحد.
- لا تضع حقل نص داخل حقل. فهو حقل أصلًا؛ وبنية التنقيح (debug) تقول ذلك. وعنصر التحكم الذي يؤطّره الحقل هو حقل إدخال النص.
- لا تستخدم حقلًا من النوع `text` وتحليلًا من عندك لتاريخ. استخدم `date`، ليأتي معه ترتيب الإعدادات المحلية ومفاتيح المقاطع وخطأ الإدخال.
- لا تكتب «(مطلوب)» في التسمية وتعيّن `required` معًا. العلامة تقول ذلك سلفًا، وقارئ الشاشة سيسمعه مرتين.
- لا تجعل الحقل الذي يُغيَّر حجمه باليد الطريقة الوحيدة لرؤية نص طويل. أعطِه من `minRows` ما يكفي ليكون نافعًا حين يُفتح.
- لا تعطِّل حقلًا لمجرد عرض قيمة لا تتغيّر. استخدم `readOnly`، ليبقى في وسع الناس أن يركّزوا عليها ويحدّدوها وينسخوها.
- لا تعيّن خط الشيفرة لحقل نص من الخارج، بالمحدِّد `::part(input)` أو بنمط من عندك، ولا تضف `dir` أو `spellcheck` إلى العنصر. استخدم `type="code"`: فالخط وحده يترك حقلًا يبدو صحيحًا وما زال يصحّح ما يُكتب.
- لا تستخدم حقل الشيفرة محرّرًا، ولا تستخدم حقل شيفرة معطَّلًا لعرض شيفرة طويلة: فالحقل المعطَّل ليس فيه مؤشر كتابة يُمرَّر به. استخدم `readOnly`، أو كتلة الشيفرة.

## إمكانية الوصول

### ما يتكفل به المكوّن

- يُحرَّر النص في عنصر النص الخاص بالمنصة، فتعمل أساليب الإدخال والإملاء والتعبئة التلقائية والتحديد والحافظة كما تعمل في سائر المنصة. والتاريخ أو الوقت هو الاستثناء المصرَّح به: صف مقاطعه من صنع الحقل نفسه.
- حقل التاريخ أو الوقت مجموعة تسمّيها التسمية. وكل مقطع زر دوّار (spin button) تسمّيه وحدته والتسمية («الشهر، تاريخ البدء»)، مع مداه وقيمته؛ والمقطع الفارغ يُقرأ نص `segmentEmptyText`.
- الحقل المطلوب يُعرض على أنه مطلوب. والعلامة نفسها مخفيّة عن التقنيات المساعدة، فلا تُقرأ مرتين؛ والنص الاختياري يُقرأ مع وصف الحقل.
- مقبض تغيير الحجم موضع توقف للتركيز تسمّيه الخاصية `resizeLabel`، ويُعرض فاصلًا (separator) قيمته عدد الأسطر. مفاتيح الأسهم والمفتاحان Home و End تغيّر الحجم، فلا شيء يتوقف على السحب، ومساحة لمسه تستوفي الحد الأدنى للهدف.
- التسمية هي الاسم المتاح للتقنيات المساعدة، مرسومةً كانت أو مخفيّة. والنص النائب ليس كذلك أبدًا.
- النص المساعد أو نص الخطأ المعروض والعدد هي وصف الحقل. وكذلك البادئة واللاحقة ما دامتا معروضتين، فتُقرأ الوحدة أو العملة مع القيمة.
- يعرض حالة التعطيل، وحالات عدم الصلاحية والمطلوب والقراءة فقط حيث تكون للمنصة. وخطأ الإدخال في حقل تاريخ أو وقت يُعرض تمامًا كما تُعرض `error`.
- زر المنتقي زر تسمّيه الخاصية `pickerLabel`، ويُعرض على أنه يفتح مربع حوار، وهو موضع توقف للمفتاح Tab بعد المقطع الأخير.
- حين يظهر خطأ أو يتغيّر والتركيز على الحقل، يُعلَن مرة واحدة، بتهذيب. والعدد يُعلَن كما هو معروض («12/40») حين تتوقف الكتابة ثانية واحدة، لا عند كل ضغطة مفتاح أبدًا.
- حقل البحث يُعرض مربع بحث (search box) حيث يكون للمنصة هذا الدور.
- حقل الشيفرة هو مربع النص نفسه الذي لكل نوع آخر، ومتعدد الأسطر مع `multiline`: لا دور ولا وصف دور ولا كلمة تقول إنه يحمل شيفرة، ولا يُعلَّم أي جزء من قيمته خطأً إملائيًّا. والمفتاح Tab يغادره دائمًا. وحيث لا تلتفّ أسطره يمرّره مؤشر الكتابة، ويُعرض التركيز على الحاوية، وهي لا تُمرَّر.
- يُعرض التركيز بحافة الحقل نفسها، سواء جاء من لوحة المفاتيح أو من مؤشر: خط داخل صندوق الحقل من الطراز stacked، والحافة الأثخن الملوَّنة للحقل من الطراز filled أو outlined. ومساحة اللمس تستوفي الحد الأدنى للهدف.
- الضغط على التسمية أو على الصندوق ينقل التركيز إلى حقل الإدخال ولا يشغّل شيئًا. والضغط على المساعدة أو نص الخطأ أو العدد لا يفعل شيئًا.
- الاسم والوصف والحالات مربوطة به تمامًا كما يربطها الحقل بأي عنصر تحكم يؤطّره. والحقل المكتوب باليد، في المستوى الأدنى، هو مربع النص نفسه.
- غياب التسمية يُبلَّغ عنه في بنيات التنقيح (debug).

فجوات معروفة في المنصات:

- تحتفظ SwiftUI و Compose و Flutter و React Native بالراية `required` التي لا ترسم علامة، وليس فيها أوضاع تغيير الحجم ولا مقبض ولا مقاطع.
- الويب: ينزاح صف المقاطع بضعة بكسلات حين يأخذ الشهر أو الدقيقة رقمه الأول؛ وقد يصدر `input` مرتين حيث يكون المقطع الأخير في الإعدادات المحلية من رقمين؛ وعلى لوحة مفاتيح Android التي على الشاشة لا يستطيع المفتاح Backspace على مقطع فارغ أن يرجع إلى الوراء؛ والصف الأعرض من حقل ضيق يفيض بدل أن يُمرَّر.
- لا يستطيع المنتج أن يفرّغ صف تاريخ نصف مملوء بتعيين `value` بالسلسلة الفارغة التي هي فيه سلفًا.
- الويب: تحت نمط التركيز بالتوهّج (glow)، توهّج الحقل من الطراز filled مدوَّر عند الزاويتين السفليين، وهما مربعتان.
- الويب: التركيب في أسلوب الإدخال (input-method composition) والتسمية المعبَّأة تلقائيًّا مختبَران في Chromium فقط.
- الويب: حقل الشيفرة الذي للقراءة فقط ولا تلتفّ أسطره يُمرَّر من لوحة المفاتيح كما يمرّر المتصفح أي نص لا يحرّره: بمؤشر الكتابة في Firefox، وبمفاتيح الأسهم في Chrome، وبالمفتاح Option مع مفاتيح الأسهم في Safari. ويعيد Firefox مثل هذا الحقل إلى حافته اليسرى حين يتغيّر اتجاه الصفحة.
- لم يبنِ SwiftUI و Compose و Flutter و React Native النوع code: فليس في `type` هناك القيمة `code`، وليس في الحقل `wrap`.
- ليس في SwiftUI حالات لعدم الصلاحية ولا للمطلوب ولا للقراءة فقط. فهي تُرسم أو تُفرض، ولا تُعلَن. والخطأ يُسمع فقط نصًّا في الوصف.
- لا يستطيع SwiftUI رؤية التركيب في أسلوب الإدخال، فتنطبق `maxLength` أيضًا على نص ما زال يُركَّب، والقيمة التي تعيّنها في أثناء التركيب لا تؤجَّل.
- في SwiftUI: النص المحدَّد يُظلَّل بصبغة مؤشر الكتابة، لا بلون التحديد الخاص بالحقل.
- يرسم SwiftUI قيمة الحقل الذي للقراءة فقط نصًّا قابلًا للتحديد، لا حقل نص.
- لا يقرأ SwiftUI المُعدِّل `.labelsHidden()` إلا من iOS 18 و macOS 15. وفي الإصدارات الأقدم ما زالت التسمية تُرسم.
- لا يستطيع React Native رؤية التركيب في أسلوب الإدخال. القيمة التي تغيّرها في أثناء التركيب، وحد `maxLength`، يُطبَّقان فورًا وقد ينهيان التركيب.
- ليس في React Native حالات لعدم الصلاحية ولا للمطلوب ولا للقراءة فقط. الخطأ يُسمع فقط نصًّا في الوصف؛ والمطلوب والقراءة فقط لا يُعلَنان.
- في React Native: الإعلانات والتعبئة التلقائية ولوحة المفاتيح لكل نوع مختبَرة بكائنات وهمية (mocks) فقط، لا على جهاز بعد.
- في React Native على iOS صبغة واحدة لمؤشر الكتابة ولتظليل التحديد. يحتفظ الحقل بلون مؤشر الكتابة، فيكون التظليل صبغة منه لا لون التحديد الخاص بالحقل.
- في React Native: توهّج الحقل من الطراز filled يتبع زاويتيه العلويين فقط، ولونا النص النائب ومؤشر الكتابة ينقلبان فورًا بدل أن يتغيّرا على مدى حركة الحالة.
- يعرض Flutter حقل البحث نوعَ إدخال للبحث، لا دور مربع البحث.
- لا يرسم Flutter مقابض تحديد ولا شريط أدوات للتحديد على Android وغيره من شاشات اللمس. الضغط المطوَّل واختصارات لوحة المفاتيح ما زالت تحدّد وتنسخ؛ و iOS يعرض قائمة نظامه.
- في Flutter: العنصر التفاعلي في منفذ البداية يأتي قبل حقل الإدخال في ترتيب التركيز، لا بعده.
- ليس في Compose حالة للمطلوب: يقرأ الحقل «`Required`» وصفًا لحالته بدلًا منها.
- في Compose: الخاصية `maxLength` والعدّاد يعدّان الأحرف كما يراها الناس، لكن تسلسلات الإيموجي والأعلام غير مختبَرة. تعمل الاختبارات على JVM تحت Robolectric، وقواعد الأحرف فيه لا تعرفها.
- في Compose: إعلانات TalkBack عن الخطأ والعدد، وأسلوب إدخال حقيقي، وخدمة تعبئة تلقائية حقيقية لم تُختبر على جهاز.

### ما عليك فعله

- اكتب تسمية تسمّي القيمة، وأبقِها حتى حين تخفيها.
- اكتب نص خطأ يقول كيف تُصحَّح القيمة، وعيِّن `error` بنفسك. على SwiftUI و React Native ذلك النص هو الطريقة الوحيدة التي يُسمع بها الخطأ. ولحقل تاريخ أو وقت اكتب أيضًا `invalidText` و `unavailableText`، وأعطِ `segmentEmptyText`: من دونه يُقرأ المقطع الفارغ بلا قيمة.
- أعطِ زر المنتقي الخاصية `pickerLabel` بلغة منتجك، وافتح المنتقي من الحدث `pickerRequest`.
- عيِّن `required` أو `optional`، وأعطِ `requiredText` و `optionalText`: على الحقل، أو مرة واحدة للمنتج كله بالاستدعاء `setWords({ requiredText, optionalText })`، كما يمكن أن تُعطى `resizeLabel` و `segmentEmptyText` بالطريقة نفسها. لا يتضمن Tanrei أي كلمة على الويب، والكلمة الناقصة يُبلَّغ عنها أثناء التطوير. انظر [كلمات المنتج](https://tanrei.chnotchy.com/ar/foundations/words/). وإلى أن يلحق SwiftUI و Compose و Flutter و React Native لا ترسم حقولها علامة، و SwiftUI و React Native لا يُعلِنان حالة المطلوب: قل «مطلوب» في التسمية هناك.
- سمِّ مقبض تغيير الحجم بالخاصية `resizeLabel`. من دونها يُرسم المقبض ويعمل، ولا اسم له.
- ضع الوحدة أو العملة في `prefixText` أو `suffixText`، لا في القيمة، لتُقرأ مع القيمة ولا تُكتب.
- لحقل الشيفرة، قل ما يجب أن تكون عليه الشيفرة في `label` و `supportingText` («محتوى طلب Webhook» و«JSON»)، وقل ما الخطأ فيها في `errorText`: فالحقل لا يعرف اللغة.
- أعطِ زر الأيقونة الذي في النهاية اسمه الخاص بلغة منتجك.
- على Compose تأتي الكلمتان «`Invalid`» و«`Required`» من موارد السلاسل النصية في المكتبة (`tanrei_invalid` و `tanrei_required`). تجاوزهما في مواردك لتترجمهما.
- على الويب يكبّر iOS Safari العرض على حقل إدخال نصه أصغر من 16 px. حقول النظام الافتراضي تستخدم نصًّا بمقاس 16 px في الحجمين؛ والطبقة التي تصغّره تعيد التكبير.
