حقل رمز التحقق
رمز يُستخدم مرة واحدة، حرف في كل خانة. اللصق يملأ كل الخانات، وحقل مخفي واحد يحمل الرمز إلى النموذج.
client - الحجم لم يُقَس بعد
حقل رمز التحقق
client - الحجم لم يُقَس بعدرمز يُستخدم مرة واحدة، حرف في كل خانة. اللصق يملأ كل الخانات، وحقل مخفي واحد يحمل الرمز إلى النموذج.
جرّبه
length
size
invalid
groupSize
الشيفرة
otp-field.tsx
import { OTPField } from 'topclassui/otp-field'
<div className="grid justify-items-start gap-2">
<label htmlFor="otp-playground-code" className="text-sm text-body">Verification code</label>
<OTPField id="otp-playground-code" />
</div>اسم التصدير هو OTPField. داخل نموذج يرسل الحقل المخفي ما كُتب حتى الآن، حتى لو كان الرمز ناقصًا.
كل الحالات، بدون تمرير الفأرة
6 حالاتأو استورده من الحزمة
topclassui/otp-field
import { OtpField } from 'topclassui/otp-field'ثبّت مرة واحدة:npm i topclassui@beta zod
أمثلة
lengthقيمته 6 افتراضيًا، ومحصور في عدد صحيح من 1 إلى 12. وgroupSizeيرسم فاصلًا بعد كل ذلك العدد من الخانات.- الأرقام هي الافتراضية: تُقبل الأرقام اللاتينية والهندية الشرقية والفارسية وتُخزَّن لاتينية، وتُحذف المسافات من اللصق.
- بعد ثمانية عناصر، خانات وفواصل معًا، ينكسر الصف عند خانات كاملة، فتبقى الخانات الاثنتا عشرة بارتفاع 44px على الهاتف.
- كل خانة مربع من مقياس العناصر، 40px عند
md، وتتخلى عن العرض قبل الارتفاع. الخانات الست تحتاج 184px. - كائن التحكم الذي يمرره Field يُفرد عليه كما هو.
basic
Six digits from your authenticator app
basic.tsx
import { OTPField } from 'topclassui/otp-field'
/** Outside a Field: a native label points at the id of the field, which is the first cell, and a hint describes it. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-2">
<label htmlFor="otp-basic-code" className="text-sm text-body">Verification code</label>
<OTPField id="otp-basic-code" aria-describedby="otp-basic-hint" />
<p id="otp-basic-hint" className="text-sm text-muted">Six digits from your authenticator app</p>
</div>
)
}
grouped
grouped.tsx
import { OTPField } from 'topclassui/otp-field'
/** Six cells in two groups of three, with a bar between them that a screen reader does not read. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-2">
<label htmlFor="otp-grouped-code" className="text-sm text-body">Verification code</label>
<OTPField id="otp-grouped-code" groupSize={3} />
</div>
)
}
form
form.tsx
import { Button } from 'topclassui/button'
import { OTPField } from 'topclassui/otp-field'
/** In a plain form: it sends code= before anything is typed, and what is typed so far after, a partial code too. */
export default function Demo() {
return (
<form className="grid justify-items-start gap-3">
<label htmlFor="otp-form-code" className="text-sm text-body">Verification code</label>
<OTPField id="otp-form-code" name="code" />
<Button type="submit">Verify</Button>
</form>
)
}
sizes
Extra smallSmallMediumLargeExtra large
sizes.tsx
import { OTPField } from 'topclassui/otp-field'
/** The five sizes, each named by the text above it. A cell gives up width before it gives up height. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-3">
<span id="otp-sizes-xs" className="text-sm text-body">Extra small</span>
<OTPField size="xs" aria-labelledby="otp-sizes-xs" defaultValue="482" />
<span id="otp-sizes-sm" className="text-sm text-body">Small</span>
<OTPField size="sm" aria-labelledby="otp-sizes-sm" defaultValue="482" />
<span id="otp-sizes-md" className="text-sm text-body">Medium</span>
<OTPField size="md" aria-labelledby="otp-sizes-md" defaultValue="482" />
<span id="otp-sizes-lg" className="text-sm text-body">Large</span>
<OTPField size="lg" aria-labelledby="otp-sizes-lg" defaultValue="482" />
<span id="otp-sizes-xl" className="text-sm text-body">Extra large</span>
<OTPField size="xl" aria-labelledby="otp-sizes-xl" defaultValue="482" />
</div>
)
}
long
long.tsx
import { OTPField } from 'topclassui/otp-field'
/** Twelve cells, the most a field takes. Past eight items the row wraps, so on a phone every cell keeps 44 px. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-2">
<label htmlFor="otp-long-code" className="text-sm text-body">Recovery code</label>
<OTPField id="otp-long-code" length={12} validationType="alphanumeric" />
</div>
)
}
بالعربية، من اليمين إلى اليسار
rtl.tsx
import { TopClassProvider } from 'topclassui/provider'
import { OTPField } from 'topclassui/otp-field'
/** Arabic, inside TopClassProvider as the root layout would mount it. The group sits at the right, under its label,
* and its cells still run left to right, as the code reads. */
export default function Demo() {
return (
<TopClassProvider direction="rtl" locale="ar">
<div dir="rtl" lang="ar">
<label htmlFor="otp-rtl-code" className="block text-sm text-body">رمز التحقق</label>
<OTPField id="otp-rtl-code" name="code" className="mt-2" />
</div>
</TopClassProvider>
)
}
الخصائص
لوحة المفاتيح وإمكانية الوصول
- سمِّه بـ
id(لتسمية<label htmlFor>) أوaria-labelledby؛ ويقع الاسم على الخانة الأولى. أماaria-labelفمرفوض. - كل خانة بعدها تُسمّى بموقعها، «الخانة 2 من 6»، بلغة المزوّد. و
aria-describedbyيذهب إلى الخانة الأولى. invalidيضبط aria-invalid على كل خانة، لا على المجموعة: يتحوّل كل خط إلى لون الخطر ويزداد سمكًا.
من اليمين إلى اليسار
الرمز يُقرأ من اليسار إلى اليمين، لذا تبقى الخانات في صفحة عربية من اليسار إلى اليمين؛ وتقع المجموعة في بداية السطر، بجانب تسميتها.
الخادم والمتصفح
مكوّن متصفح: يُعرض على الخادم ثم يُرطَّب في المتصفح.
الملفات: index.tsx, client.tsx.
على الشارة: client - الحجم لم يُقَس بعد.