Перейти к содержимому
v2.5.0
English
Русский
Документация

PinField

PinField — составной компонент для кодов фиксированной длины, таких как одноразовые коды (OTP) и PIN.

Паттерны

Подтверждение одноразовым кодом

Когда использовать:

  • пользователь вводит короткий код подтверждения из SMS, письма или приложения-аутентификатора

Заметки о композиции:

  • длина должна быть фиксированной
  • задайте autoComplete='one-time-code' на PinFieldInput, чтобы браузер мог подставить код
  • размещайте поясняющий текст или текст ошибки рядом

Компромиссы:

  • код легко просмотреть и исправить
  • более специализированный компонент, чем обычное текстовое поле
6-digit-otp.tsx · 40 строк
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 только для визуальной группировки
  • сохраняйте согласованную длину ввода

Компромиссы:

  • повторяет реальное форматирование кода
  • добавляет ещё одно решение по раскладке
grouped-code-with-separator.tsx · 22 строки
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, если бэкенд ждёт заглавные буквы
  • согласуйте маску на фронтенде с валидацией на бэкенде

Компромиссы:

  • гибко
  • если маску угадывать, легко разойтись с ожиданиями бэкенда
alphanumeric-activation-code.tsx · 29 строк
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 на фронтенде не соответствует ожиданиям бэкенда.

Как проверить

  • сравните текущую маску с форматом, который принимает бэкенд

Исправление

Обновите маску и плейсхолдеры так, чтобы они отражали реальный допустимый формат кода.