حقل إدخال الرمز لمرة واحدة
يأخذ رمزًا قصيرًا أُرسل إلى الشخص، كرمز تسجيل الدخول أو رمز التحقق، قيمةً نصية واحدة مرسومة في خانات منفصلة، فيُرى طوله وما بقي منه ناقصًا، وتستطيع المنصة أن تملأه في خطوة واحدة.
متقدّم
معظم المنتجات تستخدم One-time-code field، وهذا المكوّن جزء منه.
- الفئة
- إدخال النص
- الرموز
comp.one-time-code-input- المستوى
- أساسي
- يُستخدم في
- One-time-code field
- Web
tanrei-one-time-code-inputschedule - SwiftUI
TanreiOneTimeCodeInputradio_button_unchecked - Jetpack Compose
TanreiOneTimeCodeInputradio_button_unchecked - Flutter
TanreiOneTimeCodeInputradio_button_unchecked - React Native
OneTimeCodeInputradio_button_unchecked
مولَّد من docs/status/status.json, specs/one-time-code-input.spec.json
حقل إدخال الرمز لمرة واحدة داخل حقل، وآخر رفض المنتج رمزه
استخدم حقل إدخال الرمز لمرة واحدة (one-time-code input) لرمز قصير أرسله المنتج إلى الشخص ويطلبه منه مرة واحدة: لتسجيل الدخول، أو لتأكيد عنوان بريد إلكتروني أو رقم هاتف، أو للموافقة على عملية دفع. والخانات تُظهر طول الرمز وكم بقي منه ناقصًا.
هو حقل إدخال واحد للرمز كله، لا حقل إدخال لكل حرف. فيه قيمة نصية واحدة، وموضع توقف واحد للمفتاح Tab، ومربع نص (text box) واحد للتقنيات المساعدة؛ والخانات رسم لتلك القيمة. ولذلك تملؤه التعبئة التلقائية للرموز في المنصة في خطوة واحدة، ويصل النص الملصوق كاملًا، ويقرأ قارئ الشاشة مربع نص واحدًا له اسم.
هو مكوّن متقدم: عنصر التحكم مجرَّدًا، لمنتج يركّب حقله بنفسه. ليست له تسمية ولا مساعدة ولا نص خطأ من عنده. ومعظم المنتجات تريد حقل الرمز لمرة واحدة (one-time-code field)، وهو حقل الإدخال هذا داخل حقل، جاهزًا للاستخدام.
يُستخدم في حقل الرمز لمرة واحدة. ولتركّب حقلك بنفسك ضعه داخل حقل، فهو الذي يسمّيه ويصفه ويعلّمه مطلوبًا ويضعه في حالة الخطأ؛ والأمثلة في هذه الصفحة مكتوبة بهذه الطريقة، على مستوى واحد تحت حقل الرمز لمرة واحدة. وحيث تكون التسمية المرئية في مكان آخر، كالعنوان الرئيسي لمربع حوار، استخدمه وحده وأعطِه label، وهي لا تُرسم أبدًا.
على الويب هو <tanrei-one-time-code-input>. والمنصات الأخرى لم تنفّذه بعد.
الخاصية value هي الرمز المُدخل حتى الآن: length من الأحرف على الأكثر، وهي أرقام، أو أرقام وأحرف كبيرة مع alphanumeric، بلا فاصل، أيًّا كانت المجموعات المرسومة.
<form>
<tanrei-field label="رمز التحقق"
supporting-text="أدخِل الرمز المكوّن من 6 أرقام الذي أرسلناه إلى هاتفك."
error-text="الرمز غير صحيح. تحقق من الرسالة وحاول مرة أخرى."
required required-text="مطلوب">
<tanrei-one-time-code-input name="code" group-size="3"></tanrei-one-time-code-input>
</tanrei-field>
</form>
<script type="module">
import '@tanrei/web/components/field';
import '@tanrei/web/components/one-time-code-input';
const field = document.querySelector('tanrei-field');
const code = document.querySelector('tanrei-one-time-code-input');
// غيّر الشخص القيمة. وهي الآن القيمة الجديدة.
code.addEventListener('input', () => (field.error = false));
// مُلئت الخانة الأخيرة، أو لُصق رمز كامل أو عُبِّئ تلقائيًّا. ولا يحدث شيء آخر من تلقاء نفسه.
code.addEventListener('complete', async (e) => {
code.readOnly = true;
const right = await verify(e.detail.value);
code.readOnly = false;
field.error = !right;
});
</script>// يُستورد المكوّن المتقدّم، وهو جزء تُبنى منه مكوّنات أخرى، من المدخل advanced.
import { Field } from '@tanrei/react';
import { OneTimeCodeInput } from '@tanrei/react/advanced';
<Field label="رمز التحقق" error={wrong}
supportingText="أدخِل الرمز المكوّن من 6 أرقام الذي أرسلناه إلى هاتفك."
errorText="الرمز غير صحيح. تحقق من الرسالة وحاول مرة أخرى.">
<OneTimeCodeInput name="code" groupSize={3} value={code}
onInput={(event) => setCode(event.detail.value)}
onComplete={(event) => verify(event.detail.value)} />
</Field>أربع خانات، وثماني خانات في مجموعتين، وأحرف وأرقام، ورمز محجوب، ورمز للقراءة فقط، ورمز معطَّل
| الجزء | ما هو |
|---|---|
| الخانة | صندوق لكل حرف من الرمز، فارغ أو فيه حرف واحد. والخانة الفارغة والخانة المملوءة هما الصندوق نفسه |
| الحرف | حرف الخانة المملوءة، بنمط نص الإدخال في حقل النص وبأرقام متساوية العرض (tabular figures). ومع mask تقف مكانه العلامة التي يرسمها حقل كلمة المرور |
| الخانة النشطة | ما دام التركيز على حقل الإدخال، هي الخانة التي يذهب إليها الحرف التالي: أول خانة فارغة، أو الخانة الأخيرة حين تكون كلها مملوءة. ترسم خط التركيز داخل حافتها، وهو مؤشر التركيز لحقل الإدخال وعلامة الموضع فيه معًا |
| مؤشر الكتابة (caret) | في الخانة النشطة الفارغة. والخانة النشطة المملوءة لا ترسمه: فالحرف التالي يحلّ محل ما فيها |
| علامة المجموعة | مع groupSize، خط قصير بعد كل عدد معيَّن من الخانات. وهي رسم فقط: ليست جزءًا من القيمة ولا مما يُنسخ ولا مما يرسله النموذج |
ارتفاع الخانة كارتفاع حقل النص بالحجم medium، فيتساوى حقل إدخال الرمز وحقل النص ارتفاعًا في النموذج الواحد. وله حجم واحد ومظهر واحد؛ ونظام التصميم يعيّن ارتفاع الخانة وزواياها وتعبئتها في طبقته.
يبدأ الصف من حافة البداية، وعرضه ما تحتاج إليه خاناته: ست خانات في مجموعتين عرضها 284 في النظام الافتراضي، وهذا يتسع له عرض شاشة 320. وحيث يضيق المكان تتقاسم الخانات العرض وتصير أضيق، حتى تبلغ عرض حرف مع حشو صغير من كل جانب؛ ثم يلتفّ الصف: بين مجموعتين أولًا، بلا العلامة عند موضع الالتفاف، وبين الخانات حيث لا مجموعات. ولا تُقصّ خانة أبدًا، ولا يُرسم الرمز أصغر ليتسع له المكان.
| متى | ما يحدث |
|---|---|
| يُكتب حرف مسموح به | يملأ الخانة النشطة ويحلّ محل ما فيها، وتصير الخانة التالية نشطة. وفي الخانة الأخيرة تبقى الخانة النشطة مكانها، فيحلّ أي حرف آخر محل الأخير |
| يُكتب أي حرف غيره | لا شيء. الخانة لا تحمل إلا ما يمكن أن يحمله رمز |
| المفتاح Backspace | الخانة النشطة المملوءة تفقد حرفها؛ والفارغة يُحذف الحرف الذي قبلها. وما بعده يتقدم ليسدّ مكانه: فالقيمة لا فراغ فيها |
| مفتاحا السهم لليسار والسهم لليمين، والمفتاحان Home و End | تنقل الخانة النشطة بين الخانات المملوءة وأول خانة فارغة. ومفتاحا السهم للأعلى والسهم للأسفل لا يفعلان شيئًا |
| تحديد الكل، ثم حرف | يحلّ الحرف محل الرمز كله. ولا يمكن تحديد بعض الخانات دون غيرها |
| اللصق، أو الإفلات، أو التعبئة التلقائية، أو الإملاء | يُقرأ النص كله رمزًا واحدًا، أينما كانت الخانة النشطة |
ما يُكتب أو يُلصق يُقرأ بتسامح. أرقام أنظمة الكتابة الأخرى، والأرقام والأحرف كاملة العرض، تُقرأ بصورها في ASCII، والأحرف الصغيرة تُقرأ كبيرة؛ فالقيمة دائمًا بأحرف ASCII، ويمكن أن تُقارَن كما هي بالرمز الذي أُرسل.
النص الملصوق يفقد مسافاته وشرطاته القصيرة والطويلة: النصان 123 456 و 123-456 يصيران 123456. وفي الأرقام، يُبحث في النص الأطول عن سلسلة واحدة لا غير من الأرقام المتتالية طولها length بالضبط، فيمكن لصق رسالة كاملة، مثل «رمزك هو 123456.». وكل ما فيه لبس لا يغيّر شيئًا.
النص الذي لم يعتمده أسلوب الإدخال بعد يُرسم في الخانات مسطَّرًا، ولا يغيّر أي قيمة إلى أن يُعتمد.
| الحدث | متى |
|---|---|
input |
كل تغيير يجريه الشخص. ويحمل القيمة الجديدة |
complete |
تغيير أجراه الشخص جعل طول القيمة length من الأحرف. يصدر بعد الحدث input الخاص بذلك التغيير، مرة واحدة |
change |
غادر التركيز حقل الإدخال، أو ضُغط المفتاح Enter، والقيمة تختلف عن آخر قيمة معتمَدة |
action |
المفتاح Enter. وفي نموذج على الويب يُرسل النموذج بعده كما يُرسل من أي حقل إدخال نصي |
لا يصدر أيٌّ منها حين يعيّن المنتج value. ولا يحدث شيء آخر حين يكتمل الرمز: فحقل الإدخال لا يرسل النموذج ولا ينقل التركيز ولا يعطّل نفسه ولا يُعلِن شيئًا. وما يلي اكتمال الرمز من شأن المنتج.
البنية
البنية
empty كما ترسمه حزمة الويب.| الجزء | الوصف |
|---|---|
1 cell | One box per character of the code, empty or holding one character. The component's container: it carries the hover and the focus answer, and its tokens are the container's. |
2 character | The character a filled cell holds, or the platform's obscuring mark in its place while mask is true. |
3 caret · اختياري | Drawn in the active cell while the field has focus and that cell is empty: where the next character goes. |
4 separator · اختياري | A short line between two groups of cells. A drawing only: not part of the value and kept from assistive technology. |
الخصائص
| الخاصية | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
value | string | "" | The code entered so far: at most length characters, digits or, for alphanumeric, digits and upper-case letters, with no separator. One string, whatever the cells and groups drawn. |
length | number | 6 | How many characters the code has, and so how many cells are drawn. A whole number of 1 or more. |
type | numeric | alphanumeric | "numeric" | What a cell takes: numeric is the digits 0 to 9, with a numeric keypad; alphanumeric is digits and the letters A to Z, held in upper case, with a general keyboard. |
groupSize | number | 0 | Draws the cells in groups of this many, counted from the first, with a mark between two groups (3 for a six-character code written "123 456"). 0 draws one group. It changes the drawing only: the value has no separator. |
mask | boolean | false | Draws the platform's obscuring mark in each filled cell in place of its character, and exposes the field as protected. For a screen other people can see; a code that is used once and expires rarely needs it. |
label | string | "" | Names the field for assistive technology where no Field frames it (the visible label is a dialog headline or a step title, in the same words). Never drawn. Inside a Field leave it empty: the Field names it. |
error | boolean | false | Draws every cell in the error condition and exposes the field as invalid. A Field sets it from its own error; set it here only where no Field frames the control. What a wrong code means is the product's to say, in words, with the Field's errorText. |
disabled | boolean | false | Prevents entry and takes the field out of the focus order. Inside a Field, disable the Field, so that its label follows. |
readOnly | boolean | false | Keeps the field focusable and its value readable, and lets nothing change it: for the moment a complete code is being checked, when taking focus away would lose the place of a person who must then correct it. |
الأحداث
| الحدث | الوصف |
|---|---|
input | The person changed the value; carries the new value. Emitted for every change, not when the product sets value. |
change | The person committed a changed value (focus left the field, or the action key was pressed); carries the value. |
complete | A change by the person left the value length characters long; carries the value. Emitted after input, once for that change. The field does nothing else: checking the code is the product's. |
action | The person pressed the keyboard's action key (Enter, Return, Done). |
الحالات
السلوك
متطلبات بصيغة EARS. يُختبر تنفيذ كل منصة مقابل هذه المعرّفات. يُعرض نص المتطلبات كما ورد في ملف المواصفة، بالإنجليزية.
| المعرّف | المتطلب |
|---|---|
OTC-1 | THE one-time-code input SHALL draw one row of length cells, in the order of the code's characters, each a box at least comp.one-time-code-input.container.height high and comp.one-time-code-input.container.width wide (OTC-23), with corners of comp.one-time-code-input.container.shape (never more than half its height) eased by sys.shape.corner-smoothing, comp.one-time-code-input.container.gap from the next, filled with comp.one-time-code-input.standard.container.color. The row SHALL start at the start edge of the width its layout gives it and SHALL be as wide as its cells, gaps and group marks need; the field SHALL be as tall as its rows. THE one-time-code input SHALL draw no label, no help, no error text, no placeholder and no container around the row: a Field frames it (OTC-22). |
OTC-2 | THE one-time-code input SHALL be one field to the person, the form, the keyboard and assistive technology: it SHALL hold one value, be one stop in the focus order, edit in one native text element of the platform, so that an input method, the platform's autofill, the clipboard and dictation meet one text input, and be exposed as one text box whose value is the whole code. The cells, the caret it draws and the group marks SHALL be a drawing of that value: they SHALL NOT be exposed to assistive technology, SHALL NOT take focus one by one, and SHALL NOT be separate inputs. |
OTC-3 | THE one-time-code input SHALL draw the character at each place of value in the cell of that place, centred, on one line, in comp.one-time-code-input.input.typescale with tabular figures and in comp.one-time-code-input.standard.input.color, and SHALL leave empty every cell past the end of value. An empty cell and a filled cell SHALL have the same box and the same fill. The value SHALL never have a gap: the filled cells are always the first ones. |
OTC-4 | THE one-time-code input SHALL hold in value only the characters its type permits — WHILE type is numeric the ASCII digits 0 to 9; WHILE type is alphanumeric those digits and the letters A to Z — and SHALL read what a person types, pastes, dictates or is given by autofill leniently before deciding: a decimal digit of any script and a full-width digit or letter SHALL be read as its ASCII form, and a lower-case letter as its upper-case form. A character that is still not permitted SHALL be dropped: it SHALL NOT enter a cell, move the active cell or emit an event. The value SHALL therefore be ASCII, in upper case, and comparable as it stands with the code the product sent. |
OTC-5 | WHILE the field has focus THE one-time-code input SHALL have one active cell, the cell the next character goes to: the first empty cell and, WHILE every cell is filled, the last cell — unless the person moved it to a filled cell (OTC-8, OTC-25). WHEN focus enters by the keyboard, by a press on a Field's label or from the product THE active cell SHALL be that first empty or last cell; WHEN focus leaves, the field SHALL have no active cell. The insertion point of the native text element SHALL stand at the active cell — before its character WHILE it is filled, at the end of the value WHILE it is empty — so that assistive technology that reads where the insertion point is, and the character at it, reads the active cell. |
OTC-6 | WHEN the person types a permitted character (OTC-4) THE one-time-code input SHALL put it in the active cell, in place of the character that cell holds, and SHALL move the active cell to the next one; WHILE the active cell is the last THE active cell SHALL stay there, so that a further character replaces the last one and nothing is typed past the end. Text an input method commits SHALL be read character by character in the same way. WHILE an input method holds text it has not yet committed THE one-time-code input SHALL draw that text's characters, read by OTC-4, in the cells from the active cell on, marked as the platform marks composing text, SHALL NOT change value or emit an event for it, and SHALL remove it from the cells when the input method cancels it; the cells are the only drawing of what is typed, so text that is being composed is never left unseen. THE one-time-code input SHALL NOT move focus out of itself because the code is complete (OTC-14). |
OTC-7 | WHILE hovered THE one-time-code input SHALL render every cell from the hovered component tokens, and WHILE focused SHALL render its active cell, and that cell alone, from the focused ones (their error parts WHILE error is true), with precedence focused over hovered; unlike a button, focus gained by pointer or touch SHALL select the focused state, because a field shows where typing will go however it was focused. THE one-time-code input SHALL show focus by the active cell's focused tokens and SHALL NOT draw the focus ring: the focused outline color and width are drawn as a line inside that cell's edge, following its corners and taking no layout space, so that no cell moves as the line appears, moves to another cell or goes; WHERE sys.behavior.focus-style is glow it SHALL also draw the glow around the active cell. A hovered cell SHALL show the state layer and draw no edge; a focused cell SHALL draw no state layer. WHILE the active cell is empty and readOnly is false THE one-time-code input SHALL draw a caret centred in it, comp.one-time-code-input.caret.width wide and one line of the input's text style high, in comp.one-time-code-input.standard.caret.color (comp.one-time-code-input.standard.error.caret.color WHILE error is true), blinking as the platform's own caret does and steady WHERE motion is reduced; a filled active cell SHALL draw no caret. WHEN its state, its active cell, error or disabled changes THE one-time-code input SHALL change its colors and line widths over comp.one-time-code-input.motion.state-duration with comp.one-time-code-input.motion.state-easing, and at once WHERE motion is reduced; a character SHALL appear in its cell at once, with no motion of its own. |
OTC-8 | WHEN the person presses Left Arrow or Right Arrow THE one-time-code input SHALL move the active cell to the cell drawn on that side, in every layout direction (OTC-27), no further than the first cell on one side and the first empty cell — or the last cell WHILE all are filled — on the other; Home SHALL move it to the first cell and End to that furthest one. Up Arrow, Down Arrow, Page Up and Page Down SHALL do nothing in the field and SHALL be left to the page. THE one-time-code input SHALL NOT change the value by any of these keys. |
OTC-9 | WHEN the person presses Backspace THE one-time-code input SHALL, WHILE the active cell is filled, remove its character and keep the active cell where it is, and WHILE the active cell is empty, remove the character before it and move the active cell there; WHEN the person presses Delete it SHALL remove the active cell's character. The characters after a removed one SHALL each move one cell toward the first, so that the value keeps no gap (OTC-3). On an empty field both keys SHALL do nothing. |
OTC-10 | WHEN the person selects all with the platform's own command THE one-time-code input SHALL select the whole value and draw every filled cell as the active cell is drawn (OTC-7); a permitted character typed then SHALL replace the whole value and stand in the first cell, and Backspace or Delete SHALL empty the field. Copy SHALL take the whole value, without group marks, whichever cell is active, and cut SHALL take it and empty the field; WHILE mask is true copy and cut SHALL give nothing and cut SHALL change nothing, as the platform's protected field gives nothing and keeps its text. THE one-time-code input SHALL offer no selection of some cells only: a drag and Shift with an arrow key SHALL select nothing. |
OTC-11 | WHEN text is pasted, dropped or dictated into the field, or given to it by the platform's autofill, THE one-time-code input SHALL read the whole text as one code, wherever the active cell is: it SHALL remove white space and hyphen and dash characters, read the rest by OTC-4, and, IF every remaining character is permitted and there is at least one, replace the whole value with the first length of them. IF that fails WHILE type is numeric and the text holds exactly one run of exactly length digits that no other digit adjoins, it SHALL take that run, so that a whole message pasted with its code in it is read. Otherwise it SHALL change nothing and emit nothing. After a change the active cell SHALL be the first empty cell, or the last WHILE all are filled. |
OTC-12 | THE one-time-code input SHALL ask the platform for the code it received and for the keyboard of its type: it SHALL mark its text element as a one-time code for the platform's autofill (the web's autofill field name one-time-code; each native platform's own content type for a one-time code), so that the code offered above the keyboard or by a password manager fills the field in one step (OTC-11); WHILE type is numeric it SHALL show a numeric keypad, and WHILE type is alphanumeric a general keyboard that capitalizes every character, each without autocorrection, suggestions or spelling marks. THE one-time-code input SHALL NOT read the person's messages itself and SHALL NOT keep or offer codes entered before. |
OTC-13 | WHEN the person changes the value — by typing, removing, cutting, pasting or autofill — THE one-time-code input SHALL emit input carrying the new value, once for each change; WHEN focus leaves the field or the action key is pressed and the value differs from the value at the last commit it SHALL emit change carrying the value; WHEN the person presses the keyboard's action key (Enter, Return, Done) it SHALL emit action and, WHERE the platform has forms, leave the key to the form, which submits as it does from any text input: through its default button (BTN-30) — WHILE the form has a submit button, the platform's own or a Button of type submit, the first of them in document order is pressed, so that its click is emitted and its name and value are sent, and WHILE that button is disabled nothing is submitted; only a form with no submit button is asked directly. A key that commits or cancels an input method's composing text SHALL NOT emit action and SHALL NOT reach the form. THE one-time-code input SHALL emit none of these when the product sets value. |
OTC-14 | WHEN a change by the person leaves the value length characters long — the last empty cell was typed into, a whole code was pasted or filled, or a character of a complete code was replaced — THE one-time-code input SHALL emit complete carrying the value, after the input event of that change and once for it. It SHALL NOT emit complete when the product sets value, and SHALL do nothing else because the code is complete: it SHALL NOT submit a form, move or drop focus, disable itself, or announce anything. What follows a complete code — checking it, saying that it is wrong, moving on — is the product's. |
OTC-15 | WHILE groupSize is a whole number from 1 to length minus 1 THE one-time-code input SHALL draw, after every groupSize cells counted from the first and before the next cell, a group mark: a horizontal line comp.one-time-code-input.separator.width long and comp.one-time-code-input.separator.thickness thick, with round ends, centred on the height of the cells, comp.one-time-code-input.container.gap from the cell on each side, in comp.one-time-code-input.standard.separator.color; the last group holds the cells that remain. The mark SHALL be a drawing only: it SHALL NOT be part of value, of what is copied or of what a form submits, SHALL take no focus and no press of its own, and SHALL be kept from assistive technology. WHILE groupSize is 0 THE one-time-code input SHALL draw no mark and one even row. |
OTC-16 | WHILE mask is true THE one-time-code input SHALL draw, in each filled cell and in place of its character, the mark the platform's own protected text field draws for a character, in the character's color and text style, at once and without first showing what was typed; it SHALL expose the field as a protected text entry, so that assistive technology does not read the characters back, and SHALL keep its type's keyboard and the platform's code autofill (OTC-12). The value, the events and what a form submits SHALL be the same as without mask. |
OTC-17 | WHILE error is true — set by the product, or by the Field that frames it (FLD-8) — THE one-time-code input SHALL render every cell from the error parts of its tokens: at rest a line comp.one-time-code-input.outline.width wide inside each cell's edge in comp.one-time-code-input.standard.error.outline.color, drawn as the focused line is (OTC-7), so that the field itself is marked and not only a text below it; and it SHALL expose the field as invalid to assistive technology. THE one-time-code input SHALL never set error itself and SHALL NOT empty, select or change the value because of it: whether a wrong code is cleared is the product's to decide. The words that say what is wrong are the Field's errorText (FLD-7, FLD-9); the error color is never the only sign. |
OTC-18 | WHEN the product sets value THE one-time-code input SHALL show it, reading it by OTC-4 and keeping its first length permitted characters; IF anything was dropped it SHALL in debug builds report it. It SHALL emit no event for a value the product sets, and setting value to what it already is SHALL change nothing, the active cell included. WHEN the value is set while the field has focus THE active cell SHALL become the first empty cell, or the last WHILE all are filled. |
OTC-19 | IF length is not a whole number of 1 or more THE one-time-code input SHALL draw 6 cells, and IF groupSize is not a whole number from 0 to length minus 1 it SHALL draw one group, and in debug builds SHALL report each. WHEN length becomes smaller than the value is long THE one-time-code input SHALL keep the first length characters, without emitting an event. WHEN type names a value it does not know it SHALL behave as numeric and in debug builds report the unknown value. |
OTC-20 | WHILE disabled is true — set by the product, or by the Field that frames it (FLD-14) — THE one-time-code input SHALL NOT be focusable or editable, SHALL have no active cell and no caret, SHALL NOT emit input, change, complete or action, SHALL expose the disabled state to assistive technology, SHALL be left out of form submission on the web, and SHALL render every cell, character and group mark from the disabled component tokens (of its error parts WHILE error is true). |
OTC-21 | WHILE readOnly is true and disabled is false THE one-time-code input SHALL stay focusable, with its active cell and its focused line, and copyable (OTC-10); SHALL NOT let the person change the value by typing, removing, cutting, pasting or autofill; SHALL draw no caret; SHALL NOT emit input, change or complete; SHALL expose the read-only state to assistive technology; SHALL be submitted with its form on the web; and SHALL render as an enabled field, including its hovered and focused states. |
OTC-22 | THE one-time-code input SHALL take its name, its description and its required state from the Field that frames it, as every control a Field frames does (FLD-10, FLD-11): the Field's label is its accessible name, the Field's supporting text with, in error, the error text after it its description. WHILE label is not empty THE one-time-code input SHALL use it as the accessible name instead, drawn nowhere, for a field no Field frames or one whose visible label is elsewhere. WHILE it has either THE one-time-code input SHALL expose that one alone, over a name the product gives it on the element (aria-label or aria-labelledby); WHILE it has neither and the product gives it a name of its own on the element — aria-label, or aria-labelledby naming an element — THE one-time-code input SHALL expose that name as its accessible name; IF it has none of the three THE one-time-code input SHALL still render and work, and in debug builds SHALL report that it has no accessible name. It SHALL expose how many characters the code has only through its value and the product's own words: it SHALL say no word of its own (OTC-30). |
OTC-23 | THE one-time-code input SHALL never be wider than its layout gives it. WHEN the row needs more width than there is, the cells SHALL share the width equally and become narrower than comp.one-time-code-input.container.width, never narrower than a character of the input's text style with comp.one-time-code-input.container.padding-inline on each side; IF the row still does not fit, it SHALL wrap onto further rows comp.one-time-code-input.container.gap below, each from the start edge: between two groups first, where the group mark at the break SHALL NOT be drawn, and between any two cells where there are no groups or one group alone does not fit. A cell SHALL never be cut, drawn over another or scrolled sideways, and the code SHALL never be drawn at a smaller text size to make it fit. |
OTC-24 | WHILE the text size is enlarged THE one-time-code input SHALL grow with its characters: each cell grows in height with the character's line, keeping comp.one-time-code-input.container.height as a minimum, becomes as wide as the character and its paddings need where that is more than comp.one-time-code-input.container.width, and all cells keep one size; the row then narrows and wraps by OTC-23. At 200% in a layout 288 wide no character SHALL be lost, cut or laid over another part, and nothing SHALL need scrolling in two directions. |
OTC-25 | WHEN the person presses a cell, a group mark or the space between cells THE one-time-code input SHALL take focus and make the pressed cell the active cell WHILE it is filled, and otherwise the first empty cell; it SHALL change nothing else and SHALL draw no press answer, because a press on a field is not an action. WHERE a cell is shorter than the minimum target THE one-time-code input SHALL extend the row's hit area vertically to sys.target.touch for touch input and sys.target.pointer for fine pointers, without changing its visual size; a platform that cannot tell the input type SHALL use sys.target.touch. |
OTC-26 | WHERE the platform draws with a person's own forced colors (the web's forced-colors mode, and a platform's equivalent where it has one) THE one-time-code input SHALL draw an edge comp.one-time-code-input.outline.width wide in the platform's control text color around every cell, that edge in the platform's highlight color at the focused width around the active cell, its characters, masks and group marks in the platform's text color and its caret in that color, and a disabled field in the platform's disabled text color; it SHALL rely on no color of its own to show an error, which is carried by the Field's words and the invalid state (OTC-17). |
OTC-27 | WHERE the layout direction is right-to-left THE one-time-code input SHALL keep the cells a left-to-right run: the first character of the code in the leftmost cell of its row, the group marks between the same cells, Right Arrow moving to the cell on the right and Left Arrow to the cell on the left, because a code is a sequence of digits and Latin letters that is written, sent and read aloud left to right in every script and digits are never reversed. Only the row's place SHALL follow the layout: the row, and every row of a wrapped code, SHALL start at the right edge of the width its layout gives it, where the Field's label and help start. A wrapped code SHALL read from the top row down in both directions. |
OTC-28 | THE one-time-code input SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the field is shown THE one-time-code input SHALL draw itself for the new direction at once, without a motion of its own, keeping its value, its active cell and its focus. |
OTC-29 | WHERE the platform has forms (the web) THE one-time-code input SHALL take part in them as a native text input does: it takes name, submits its value — the code alone, without group marks — or an empty string WHILE it holds none, restores it on navigation, resets to the value it was first given, and reports to the form's constraint validation a missing value WHILE its Field says it is required and it is empty. It SHALL report nothing for a code that is shorter than length: an unfinished code is the product's to refuse. |
OTC-30 | THE one-time-code input SHALL have no words of its own: it SHALL draw no word in any language and expose none. Its name is the Field's label or its own label, each the product's (OTC-22); what a required, a wrong or an expired code is called is the Field's requiredText, supportingText and errorText; the group mark and the mask are marks, not words. It SHALL read no key of the product's words. |
OTC-31 | 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 one-time-code input 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 one-time-code input is invalid — except those the one-time-code input owns (aria-disabled), which it SHALL move and not expose. 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 one-time-code input SHALL take it off that element. WHEN the product sets an aria- attribute the one-time-code input owns THE one-time-code input SHALL report it in debug builds. |
مطابقة الأسماء بين المنصات
التكافؤ لا يعني واجهات برمجية متطابقة. تعبّر كل منصة عن العقد نفسه بأسلوبها.
| المواصفة | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| المكوّن | tanrei-one-time-code-input | TanreiOneTimeCodeInput | TanreiOneTimeCodeInput | TanreiOneTimeCodeInput | OneTimeCodeInput |
value · الخاصية | value | code | value | controller | value |
length · الخاصية | length | length | length | length | length |
type · الخاصية | type | type | type | type | type |
groupSize · الخاصية | groupSize | groupSize | groupSize | groupSize | groupSize |
mask · الخاصية | mask | isMasked | masked | obscureText | secureTextEntry |
label · الخاصية | label | label | label | semanticLabel | accessibilityLabel |
error · الخاصية | error | error | isError | isError | error |
disabled · الخاصية | disabled | disabled | enabled | enabled | disabled |
readOnly · الخاصية | readOnly | readOnly | readOnly | readOnly | readOnly |
input · الحدث | input | code | onValueChange | onChanged | onChangeText |
change · الحدث | change | onCommit | onCommit | onCommit | onEndEditing |
complete · الحدث | complete | onComplete | onComplete | onCompleted | onComplete |
action · الحدث | action | onSubmit | keyboardActions | onSubmitted | onSubmitEditing |
| ملاحظات | A control, so a custom element with a shadow root, form-associated (static formAssociated = true) as the text field is: it takes name, submits the code, restores and resets it, follows <fieldset disabled> and reports valueMissing (OTC-29). <tanrei-field label="Verification code" supporting-text="…" error-text="…"><tanrei-one-time-code-input name="code" group-size="3"></tanrei-one-time-code-input></tanrei-field>: the field is the one element in the Field's default slot and asks it for its name, description, invalid, required and disabled states with the tanrei-field-connect event, as every Tanrei control does. In the shadow root there is exactly one <input type="text"> (type="password" while mask is set), laid over the whole row, with transparent text and no caret of its own, carrying autocomplete="one-time-code", inputmode="numeric" ("text" with autocapitalize="characters" for alphanumeric), autocorrect="off", spellcheck="false", enterkeyhint="done", and aria-label, aria-description, aria-invalid, aria-required and aria-readonly set on that element — not through ElementInternals, which axe cannot see. It has no maxlength and no pattern: the browser would cut or refuse a code pasted or filled with a space in it before the element could read it (OTC-11); the element reads and cuts in beforeinput and input. The cells, the caret and the group marks are aria-hidden elements under the input, drawn from the value; the caret is the element's own, blinking with a CSS animation that prefers-reduced-motion: reduce stops. input is a composed, bubbling CustomEvent whose detail.value is the code; the native input's own input event is stopped at the shadow root. change, complete and action are composed, bubbling events (the host's value is set before each fires). Enter is left to the native input, so a form submits implicitly as from any text input. Attributes are kebab-case (group-size) except readonly, which keeps HTML's name. The host is display: block; the row is a wrapping flex row with direction: ltr whatever the page's, placed at the inline start of the host by the page's direction. Tabular figures are font-variant-numeric: tabular-nums. Under forced-colors: active each cell has a ButtonText border, the active one Highlight. Before the element is defined it has no size and shows nothing: a page that must not jump gives the tag a block size of the cell height in its own stylesheet, and a page that must work without script uses a plain <input autocomplete="one-time-code" inputmode="numeric">, which this element is a drawing of. The product may fill value itself from the browser's own retrieval of a code from a message (the WebOTP API); the element does not call it, because the message's form and the permission are the product's. Words: the element has no words of its own and reads no key of setWords(). | TanreiField("Verification code") { TanreiOneTimeCodeInput(code: $code, length: 6, groupSize: 3, onComplete: verify) }. code is a Binding<String>, written on every change, which is the input event. Built on one TextField (SecureField while masked) laid over the drawn cells, with .textContentType(.oneTimeCode), so that the code from a message is offered above the keyboard, .keyboardType(.numberPad) (.asciiCapable with .textInputAutocapitalization(.characters) for alphanumeric) and .autocorrectionDisabled(). disabled follows .disabled(_:), action is .onSubmit, label is .accessibilityLabel where no TanreiField gives one (it reads \.tanreiField). The cells are hidden from accessibility; the row is laid out with .environment(\.layoutDirection, .leftToRight) and placed by the surrounding direction. | TanreiField(label = "Verification code") { TanreiOneTimeCodeInput(value = code, onValueChange = { code = it }, onComplete = ::verify) }. One BasicTextField whose decorationBox draws the cells from the value; KeyboardOptions(keyboardType = KeyboardType.NumberPassword, autoCorrectEnabled = false) (KeyboardType.Ascii with KeyboardCapitalization.Characters for alphanumeric), semantics { contentType = ContentType.SmsOtpCode } for the platform's autofill, and VisualTransformation for the mask. enabled is the inverse flag; the name, the description and isError come from LocalTanreiFieldState where a TanreiField frames it. The row is drawn under CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) and placed by the surrounding direction. | TanreiField(labelText: 'Verification code', child: TanreiOneTimeCodeInput(controller: code, groupSize: 3, onCompleted: verify)). One EditableText under the drawn cells with autofillHints: [AutofillHints.oneTimeCode], keyboardType: TextInputType.number (TextInputType.visiblePassword with TextCapitalization.characters for alphanumeric), autocorrect: false, enableSuggestions: false and an input formatter that reads by OTC-4. enabled is the inverse flag; the name and the states come from TanreiFieldScope where a TanreiField frames it. The row is wrapped in Directionality(textDirection: TextDirection.ltr) and aligned by the surrounding Directionality. | <Field label="Verification code"><OneTimeCodeInput value={code} onChangeText={setCode} groupSize={3} onComplete={verify} /></Field>. One transparent TextInput over the drawn cells with textContentType="oneTimeCode" (iOS) and autoComplete="sms-otp" (Android; "one-time-code" on iOS), keyboardType="number-pad" ("default" with autoCapitalize="characters" for alphanumeric), autoCorrect={false} and caretHidden. The cells are importantForAccessibility="no" and accessibilityElementsHidden. The name and the states come from FieldContext where a Field frames it. The row sets direction: "ltr" and is aligned by the app's direction. |
الرموز
| الرمز | يشير إلى | القيمة المحلولة (فاتح) |
|---|---|---|
--tanrei-comp-one-time-code-input-caret-width | sys.border.hairline | 1px |
--tanrei-comp-one-time-code-input-container-gap | sys.space.space75 | 6px |
--tanrei-comp-one-time-code-input-container-height | — | 48px |
--tanrei-comp-one-time-code-input-container-padding-inline | sys.space.space50 | 4px |
--tanrei-comp-one-time-code-input-container-shape | sys.shape.corner.small | 6px |
--tanrei-comp-one-time-code-input-container-width | sys.space.space500 | 40px |
--tanrei-comp-one-time-code-input-disabled-outline-width | — | 1px |
--tanrei-comp-one-time-code-input-focused-outline-width | — | 2px |
--tanrei-comp-one-time-code-input-hovered-outline-width | — | 1px |
--tanrei-comp-one-time-code-input-motion-state-duration | sys.motion.role.state.default | 250ms |
--tanrei-comp-one-time-code-input-motion-state-easing | sys.motion.easing.state | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-one-time-code-input-outline-width | sys.border.hairline | 1px |
--tanrei-comp-one-time-code-input-separator-thickness | sys.border.hairline | 1px |
--tanrei-comp-one-time-code-input-separator-width | sys.space.space100 | 8px |
--tanrei-comp-one-time-code-input-standard-caret-color | sys.color.primary | |
--tanrei-comp-one-time-code-input-standard-container-color | sys.color.surface-container-highest | |
--tanrei-comp-one-time-code-input-standard-disabled-caret-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-container-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-error-caret-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-error-container-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-error-input-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-error-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-error-separator-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-error-state-layer-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-input-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-separator-color | — | |
--tanrei-comp-one-time-code-input-standard-disabled-state-layer-color | — | |
--tanrei-comp-one-time-code-input-standard-error-caret-color | sys.color.error | |
--tanrei-comp-one-time-code-input-standard-error-container-color | sys.color.surface-container-highest | |
--tanrei-comp-one-time-code-input-standard-error-input-color | sys.color.on-surface | |
--tanrei-comp-one-time-code-input-standard-error-outline-color | sys.color.error | |
--tanrei-comp-one-time-code-input-standard-error-separator-color | sys.color.on-surface-variant | |
--tanrei-comp-one-time-code-input-standard-error-state-layer-color | comp.one-time-code-input.standard.error.input.color | |
--tanrei-comp-one-time-code-input-standard-focused-caret-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-container-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-error-caret-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-error-container-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-error-input-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-error-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-error-separator-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-error-state-layer-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-input-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-separator-color | — | |
--tanrei-comp-one-time-code-input-standard-focused-state-layer-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-caret-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-container-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-error-caret-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-error-container-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-error-input-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-error-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-error-separator-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-error-state-layer-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-input-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-separator-color | — | |
--tanrei-comp-one-time-code-input-standard-hovered-state-layer-color | — | |
--tanrei-comp-one-time-code-input-standard-input-color | sys.color.on-surface | |
--tanrei-comp-one-time-code-input-standard-outline-color | — | |
--tanrei-comp-one-time-code-input-standard-separator-color | sys.color.on-surface-variant | |
--tanrei-comp-one-time-code-input-standard-state-layer-color | comp.one-time-code-input.standard.input.color | |
--tanrei-comp-one-time-code-input-input-typescale | sys.typescale.body-large | 400 16px/1.625 |
نماذج الاختبار
عروض مرجعية. تلتقط كل المنصات لقطة لكل نموذج بالمعرّف نفسه حتى يمكن مقارنة النتائج.
empty
label: Verification code partial
value: 123 label: Verification code complete
value: 123456 label: Verification code grouped-empty
groupSize: 3 label: Verification code grouped-partial
value: 1234 groupSize: 3 label: Verification code grouped-complete
value: 123456 groupSize: 3 label: Verification code length-4
value: 4821 length: 4 label: Verification code length-8-grouped
value: 12345678 length: 8 groupSize: 4 label: Verification code alphanumeric-grouped
value: A7K93Q type: alphanumeric groupSize: 3 label: Verification code masked
value: 1234 mask: true label: Verification code error
value: 123456 label: Verification code error: true error-grouped-empty
groupSize: 3 label: Verification code error: true disabled
label: Verification code disabled: true disabled-value
value: 123456 groupSize: 3 label: Verification code disabled: true disabled-error
value: 123456 label: Verification code error: true disabled: true read-only
value: 123456 label: Verification code readOnly: true grouped-partial-rtl
value: 123 groupSize: 3 label: Verification code direction: rtl error-rtl
value: 123456 label: Verification code error: true direction: rtl grouped-ja
value: 123456 groupSize: 3 label: 確認コード مولَّد من specs/one-time-code-input.spec.json, tokens/comp/one-time-code-input.tokens.json, design/tokens/
- العنصر مرتبط بالنماذج (form-associated). يأخذ
nameويرسل الرمز وحده، أو سلسلة فارغة. ويعود عند إعادة الضبط إلى قيمة خاصية HTMLvalue، ويبلّغ بأن القيمة ناقصة ما دام حقله يقول إنه مطلوب وهو فارغ. والرمز الأقصر منlengthلا يُبلَّغ عنه بشيء: رفض الرمز غير المكتمل من شأنك. - في جذر الظل (shadow root) عنصر
<input>واحد لا غير، معهautocomplete="one-time-code"وinputmode="numeric"(ومعalphanumericالقيمةtextمع تكبير الأحرف)؛ ومعmaskيكون حقل إدخال لكلمة المرور. وليس لهmaxlengthولاpattern: فالمتصفح كان سيقصّ رمزًا لُصق وفيه مسافة قبل أن يُقرأ. - الأحداث
inputوchangeوcompleteوactionمن النوع CustomEvent ومعهاdetail.value. ألغِ الحدثactionلتمنع إرسال النموذج. - خاصية HTML المقابلة للخاصية
readOnlyهيreadonly، والمقابلة للخاصيةgroupSizeهيgroup-size. - مؤشر الكتابة من رسم العنصر نفسه. وحيث يعرض أسلوب الإدخال نافذة مرشَّحات، يضعها المتصفح عند نص حقل الإدخال الأصلي، في بداية الصف، لا عند الخانة النشطة.
- العنصر لا يقرأ رسائل الشخص. وللمنتج أن يطلب بنفسه من المتصفح رمز رسالة ثم يعيّن
value. - قبل أن يُعرَّف العنصر لا يكون له حجم. احجز ارتفاع خانة. والصفحة التي يجب أن تعمل بلا سكربت تستخدم عنصر
<input autocomplete="one-time-code" inputmode="numeric">عاديًّا، وما هذا العنصر إلا رسم له.
| الجانب | حقل إدخال الرمز لمرة واحدة | حقل النص |
|---|---|---|
| يحمل | رمزًا قصيرًا معروف الطول، أُرسل إلى الشخص ويعيد كتابته مرة واحدة | أي نص |
| يعرض | خانة لكل حرف: طول الرمز، وكم بقي منه ناقصًا | النص |
| يقبل | أرقامًا، أو أرقامًا وأحرفًا كبيرة | أي شيء |
حقل النص الذي معه autocomplete="one-time-code" يُدخل الرمز إدخالًا صحيحًا أيضًا، وهو الاختيار الصحيح حيث لا تُراد الخانات. أما كلمة المرور، والرقم السري الذي اختاره الشخص، ومفتاح الاسترداد أو مفتاح الترخيص، ورقم البطاقة، والرمز البريدي فتوضع في حقول نص: فليس لها طول قصير ثابت يستحق الرسم، أو يجب ألا تُعرض في خانات. والعدد الذي يقرؤه المنتج عددًا يوضع في حقل عدد.
- استخدم حقل الرمز لمرة واحدة حيث لا تحتاج إلا إلى تسمية وخانات ومساعدة وخطأ. ولا تكتب باليد حقلًا بداخله حقل الإدخال هذا إلا لترتيب لا يقدّمه حقل الرمز لمرة واحدة.
- ضع حقل الإدخال داخل حقل، وقل في
supportingTextكم حرفًا يُنتظر وإلى أين أُرسل الرمز. - ارسم المجموعات كما تكتبها الرسالة:
groupSize="3"لرمز أُرسل في الصورة «123 456». - قل بالكلمات إن الرمز خاطئ، بالخاصيتين
errorوerrorTextفي الحقل. وقرّر بنفسك هل يُمسح الرمز الخاطئ: فكثيرًا ما يكون الخطأ في رقم واحد. - استخدم
readOnlyلاdisabledما دام الرمز المكتمل قيد التحقق. فحقل الإدخال المعطَّل يفقد التركيز، والشخص الذي عليه بعد ذلك أن يصحّح الرمز يفقد موضعه. - ضع بجانب حقل الإدخال طريقة طلب رمز جديد، وأي مهلة زمنية. وهما زر ونص من عندك.
- إن كنت تتحقق من الرمز أو ترسل النموذج عند الحدث
complete، فقل ذلك قبل حقل الإدخال.
- لا تبنِ إدخال الرمز من حقل إدخال لكل حرف. فقارئ الشاشة يجد عدة مربعات نص بلا أسماء، والتعبئة التلقائية واللصق لا يستطيعان ملأها.
- لا تمنع اللصق، محجوبًا كان الرمز أو غير محجوب. فالرمز الذي يجب أن يُنقل بالنظر اختبار للذاكرة.
- لا تنقل التركيز ولا ترسل النموذج قبل أن تخبر الشخص.
- لا تستخدم
maskبحكم العادة. فالرمز الذي يُستخدم مرة واحدة وتنتهي صلاحيته قلّما يحتاج إلى إخفاء، وإخفاؤه يجعل رؤية الخطأ أصعب. - لا تستخدم
labelداخل حقل. فالحقل هو الذي يسمّي عنصر التحكم.
- الدور
textbox- التسمية
- One text box. Its accessible name is the label of the Field that frames it, or its own label where no Field does; its description is the Field's supporting text with, in error, the error text after it. Its value is the whole code as one string. It is exposed as invalid while error is true, required while its Field says so, read-only while readOnly is true, and as a protected text entry while mask is true. The cells, the caret and the group marks are not exposed.
- الحد الأدنى للهدف
- تستوفي مساحة اللمس الحد الأدنى لحجم الهدف حتى لو كان الحجم المرئي أصغر. minimum 32px · pointer 44px · spacing 8px · touch 48px
لوحة المفاتيح
| المفاتيح | الإجراء |
|---|---|
| Tab / Shift+Tab | Moves focus to the field, which is one stop however many cells it draws, and on from it. |
| A permitted character | Fills the active cell, replacing what it holds, and moves to the next cell (OTC-6). Other characters do nothing (OTC-4). |
| Left Arrow / Right Arrow | Move the active cell to the cell on that side, in every layout direction, among the filled cells and the first empty one (OTC-8). |
| Home / End | Move the active cell to the first cell, or to the first empty cell (the last cell while all are filled). |
| Backspace / Delete | Remove a character; the ones after it move up, so the value keeps no gap (OTC-9). |
| The platform's select all, copy, cut and paste | Act on the whole code: paste replaces it from the first cell, read leniently (OTC-10, OTC-11). |
| Enter | Emits action, commits a changed value, and submits the enclosing form on the web. |
ملاحظات
- One field, not one input per character. A row of separate inputs is a group of unnamed text boxes to a screen reader, breaks the platform's code autofill and paste, turns Backspace and the arrow keys into focus management, and gives a form several values for one answer. Here the cells are a drawing of one native text element.
- For a short code sent to the person and typed back once. A password, a PIN the person chose, a recovery or licence key and a card number are text fields with the matching type and autofill name; a number the product reads as a number is a number field.
- It has no label, help or error text of its own: a Field frames it (FLD-1 to FLD-24) and is where a product says how many characters to expect ("Enter the 6-digit code we sent to …"), that the code was wrong, and that it is required. Errors are words (WCAG 3.3.1, 1.4.1).
- Never moves focus or submits by itself when the code is complete (OTC-14): a change of context on input (WCAG 3.2.2) is the product's decision, taken with the complete event, and a product that submits on complete should say so before the field.
- Codes expire. Where a product limits the time to enter one, the limit, its extension and the way to ask for a new code are the product's, beside the field (WCAG 2.2.1); the field has no timer and no resend control.
- A code that must be copied from another place is a cognitive test unless it can be pasted or filled: paste and the platform's autofill always work and are never blocked, masked or not (WCAG 3.3.8).
- The active cell's focused line is the focus indicator. A design system must keep it visible: without it nothing shows where a replaced character will go.
- The cells are a left-to-right run in a right-to-left layout (OTC-27); the row stands at the start edge with the Field's label.
- Web: a touch browser zooms the page into an input whose text is smaller than 16 px. The character style is 16 px in the default system; a layer that sets a smaller style brings the zoom back.
- Heights are minimums: at 200% text size the cells grow and the row narrows or wraps (OTC-23, OTC-24); nothing is cut (WCAG 1.4.4, 1.4.10).
- Not pressable: a press focuses the field and is not an action (OTC-25), so BTN-8, BTN-9 and BTN-10 are not copied.
- How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.
مولَّد من specs/one-time-code-input.spec.json, tokens/sys/measure.tokens.json
- هو مربع نص واحد. اسمه تسمية الحقل، أو
labelالخاصة به حيث لا يحيط به حقل؛ ووصفه النص المساعد أو نص الخطأ المعروض في الحقل؛ وقيمته الرمز كله سلسلة نصية واحدة. - يُعرَض للتقنيات المساعدة على أنه غير صالح ما دام في حالة الخطأ، وعلى أنه مطلوب ما دام حقله يقول ذلك، وعلى أنه للقراءة فقط ما دامت
readOnlyبالقيمة true، وعلى أنه حقل كلمة مرور ما دامتmaskبالقيمة true. - الخانات ومؤشر الكتابة وعلامات المجموعات مخفيّة عن التقنيات المساعدة ولا تأخذ التركيز.
- موضع الإدراج الأصلي (insertion point) يقف عند الخانة النشطة، وقبل حرفها ما دامت مملوءة، فقارئ الشاشة الذي يقرأ الحرف الذي عند موضع الإدراج يقرأ الخانة المرسومة نشطة.
- هو موضع توقف واحد للمفتاح Tab، أيًّا كان عدد الخانات التي يرسمها.
- حقل الإدخال نفسه لا يُعلِن شيئًا: لا تغييرًا ولا اكتمال رمز. والخطأ الذي يظهر يُعلِنه الحقل المحيط به.
- المفتاح الذي يعتمد نص أسلوب الإدخال أو يلغيه ليس مفتاح الإجراء، ولا يرسل النموذج.
- مساحة اللمس تستوفي الحد الأدنى للهدف. والضغطة تنقل التركيز إلى حقل الإدخال، وتجعل الخانة المضغوطة نشطة ما دامت تلك الخانة مملوءة.
- عند تكبير النص إلى 200% تكبر الخانات مع أحرفها وتصير أضيق وتلتفّ؛ ولا يُقصّ شيء ولا يُمرَّر شيء جانبيًّا.
- في الألوان المفروضة (forced colors) تكتسب كل خانة حافة، وحافة الخانة النشطة بلون التحديد في النظام (highlight). ولا يدل على الخطأ أي لون من ألوان حقل الإدخال نفسه.
- في تخطيط من اليمين إلى اليسار تبقى الخانات صفًّا من اليسار إلى اليمين، فالأرقام لا تُعكس أبدًا، ويقف الصف عند الحافة اليمنى، تحت تسمية الحقل.
- ليست له كلمات من عنده، بأي لغة.
فجوات معروفة على الويب:
- ما تقوله قارئات الشاشة حين يُكتب رمز ويُستبدل ويُلصق قُرئ من أشجار إمكانية الوصول في المتصفحات، ولم يُسمع بقارئ شاشة.
- أساليب الإدخال اختُبرت بتشغيلها في Chromium، وفي Firefox و Safari بأحداثها وحدها.
- قبل أن يُعرَّف العنصر لا يُرسم شيء.
- أعطِ عنصر التحكم اسمًا: تسمية الحقل المحيط به، أو
labelالخاصة به حيث تكون التسمية المرئية في مكان آخر، وبالكلمات نفسها. - قل بالكلمات ما المنتظر: كم حرفًا، وإلى أين أُرسل الرمز. فالخانات لا تُظهر الطول إلا لمن يراها.
- قل إن الرمز خاطئ أو منتهي الصلاحية أو مطلوب بالخصائص
errorTextوsupportingTextوrequiredفي الحقل. واللون ليس الدليل الوحيد أبدًا. - حيث يكون وقت إدخال الرمز محدودًا، قل ذلك، وأتِح للشخص أن يطلب وقتًا إضافيًّا أو رمزًا جديدًا.