Паттерны
Подтверждение одноразовым кодом
Когда использовать:
- пользователь вводит короткий код подтверждения из SMS, письма или приложения-аутентификатора
Заметки о композиции:
- длина должна быть фиксированной
- задайте
autoComplete='one-time-code'наPinFieldInput, чтобы браузер мог подставить код - размещайте поясняющий текст или текст ошибки рядом
Компромиссы:
- код легко просмотреть и исправить
- более специализированный компонент, чем обычное текстовое поле
import { Button, Label, PinField, PinFieldInput, PinFieldSlot, Text } from '@vega-ui/react';
import { FormEvent, useId, useState } from 'react';
export default function Example6DigitOtp() {
const id = useId();
const [submitted, setSubmitted] = useState('');
const onSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
setSubmitted(String(new FormData(event.currentTarget).get('otp')));
};
Сгруппированный устаревший код
Когда использовать:
- код визуально разбит на группы в продукте или во внешнем источнике, откуда пользователи его копируют
Заметки о композиции:
- используйте
PinFieldSeparatorтолько для визуальной группировки - сохраняйте согласованную длину ввода
Компромиссы:
- повторяет реальное форматирование кода
- добавляет ещё одно решение по раскладке
import { Label, PinField, PinFieldInput, PinFieldSeparator, PinFieldSlot } from '@vega-ui/react';
import { useId } from 'react';
export default function GroupedCodeWithSeparator() {
const id = useId();
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-3)', width: '100%', maxWidth: 320 }}>
<Label htmlFor={id}>Code from your authenticator app</Label>
<PinField maxLength={6}>
<PinFieldInput id={id} name='totp' autoComplete='one-time-code' />
<PinFieldSlot index={0} />Буквенно-цифровой код активации
Когда использовать:
- код принимает буквы и цифры
Заметки о композиции:
- передайте подходящую маску
- нормализуйте регистр в
onChangeValue, если бэкенд ждёт заглавные буквы - согласуйте маску на фронтенде с валидацией на бэкенде
Компромиссы:
- гибко
- если маску угадывать, легко разойтись с ожиданиями бэкенда
import { Label, PinField, PinFieldInput, PinFieldSlot, Text } from '@vega-ui/react';
import { useId, useState } from 'react';
export default function AlphanumericActivationCode() {
const id = useId();
const [code, setCode] = useState('');
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-3)', width: '100%', maxWidth: 320 }}>
<Label htmlFor={id}>Activation code from the box</Label>
<PinField
mask={/^[A-Za-z0-9]+$/}Сравнение
Быстрое правило выбора
Используйте PinField для коротких кодов фиксированной длины, которым помогает сегментированное отображение. Используйте PasswordField для секретных строк и TextField для обычного текста.
PinField и PasswordField
Используйте PinField, когда:
- значение — одноразовый код (OTP) или короткий код подтверждения
Используйте PasswordField, когда:
- значение — более длинная секретная строка с возможностью показать или скрыть её
PinField и TextField
Используйте PinField, когда:
- сегментация упрощает чтение и ввод
Используйте TextField, когда:
- поле — обычный свободный ввод
Выбирайте этот компонент, когда
- длина кода фиксированная и небольшая
- сегментированный ввод помогает просматривать и исправлять код
- вставка и автопереход к следующему слоту — ожидаемая часть UX
Не выбирайте этот компонент, когда
- значение произвольное
- полю нужно обычное редактирование текста, а не ввод по слотам
Решение проблем
Ввод не обновляет видимые слоты
Симптом
Сегментированный интерфейс рендерится, но введённые символы не появляются в слотах.
Вероятная причина
В композиции нет PinFieldInput.
Как проверить
- изучите отрендеренную композицию
- убедитесь, что
PinFieldInputнаходится внутри корня
Исправление
Добавьте PinFieldInput внутрь PinField.
Порядок слотов кажется неправильным или каретка движется странно
Симптом
Стрелки или ввод словно попадают не в тот слот.
Вероятная причина
Индексы слотов отрендерены не по возрастанию.
Как проверить
- изучите последовательность слотов
- сравните её с
maxLength
Исправление
Рендерите элементы PinFieldSlot по возрастанию индекса и согласуйте их с задуманной длиной кода.
Бэкенд отклоняет коды, которые в интерфейсе выглядят корректно
Симптом
Пользователи могут ввести код, но отправка не проходит из-за несоответствия формата.
Вероятная причина
mask на фронтенде не соответствует ожиданиям бэкенда.
Как проверить
- сравните текущую маску с форматом, который принимает бэкенд
Исправление
Обновите маску и плейсхолдеры так, чтобы они отражали реальный допустимый формат кода.