FieldCode

Поле ввода одноразового кода (OTP): codeLength ячеек на FieldText из @cloud-ru/ds-fields, автопереход фокуса при вводе, вставка кода целиком из буфера, колбек onComplete при заполнении всех ячеек. Опционально — кнопка повторной отправки кода с таймером (resendCode) и хук валидации useFieldCodeValidate.

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

  • Подтверждение по SMS/email-коду: пользователь вводит фиксированное число цифр.
  • Нужен автопереход фокуса между ячейками и вставка кода целиком.

Когда не нужен FieldCode:

  • Числовой код как обычная строка без ячеек — FieldMask с маской code.

Анатомия

Size (default m)

Размер ячеек и подписи наследуется от FieldDecorator:

  • s — компактный (ячейка 32px).
  • m — средний (ячейка 40px).
  • l — крупный (ячейка 52px).

Слоты и состояния

  • label — заголовок поля.
  • error / invalidCode — текст ошибки; error приоритетнее.
  • showEmptyChars — подсветка пустых ячеек (состояние «код не дописан»).
  • spacing — визуальный разрыв после указанных индексов ([2] для формата XXX XXX).
  • stretchCells — ячейки делят всю ширину контейнера; иначе фиксированная ширина по size.
  • resendCode — кнопка повторной отправки: заблокирована с таймером mm:ss, пока secondsToNextResend > 0.

Imperative ref (FieldCodeRef)

  • moveFocus(index) — перенести фокус на ячейку.
  • blurFields() — снять фокус со всех ячеек.
  • resetCode() — сбросить значение.

Примеры использования

Базовый

БазовыйUncontrolled-ввод кода с onComplete.
Введите 6 цифр
tsx
import { FieldCode } from '@cloud-ru/ds-uikit-product-fields-predefined';
import { useState } from 'react';

export function FieldCodeBasic() {
  const [value, setValue] = useState('');
  const [completed, setCompleted] = useState('');

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12, alignItems: 'center' }}>
      <FieldCode codeLength={6} label='Код подтверждения' value={value} onChange={setValue} onComplete={setCompleted} />
      <span>{completed ? `Код введён: ${completed}` : 'Введите 6 цифр'}</span>
    </div>
  );
}

Валидация

ВалидацияХук useFieldCodeValidate: пустое значение и неполный код.
tsx
import { FieldCode, useFieldCodeValidate } from '@cloud-ru/ds-uikit-product-fields-predefined';
import { useState } from 'react';

const CODE_LENGTH = 6;

export function FieldCodeValidation() {
  const [value, setValue] = useState('');
  const [touched, setTouched] = useState(false);
  const validateCode = useFieldCodeValidate({ codeLength: CODE_LENGTH });

  const handleChange = (next: string) => {
    setValue(next);
    setTouched(true);
  };

  return (
    <FieldCode
      codeLength={CODE_LENGTH}
      label='Код подтверждения'
      value={value}
      onChange={handleChange}
      error={touched ? validateCode(value) : undefined}
      showEmptyChars={touched}
    />
  );
}

Повторная отправка

Повторная отправкаresendCode c таймером обратного отсчёта.
tsx
import { FieldCode } from '@cloud-ru/ds-uikit-product-fields-predefined';
import { useEffect, useState } from 'react';

const RESEND_COUNTDOWN_SECONDS = 10;

export function FieldCodeResend() {
  const [value, setValue] = useState('');
  const [secondsToNextResend, setSecondsToNextResend] = useState(RESEND_COUNTDOWN_SECONDS);

  useEffect(() => {
    if (secondsToNextResend <= 0) {
      return;
    }

    const timerId = window.setTimeout(() => setSecondsToNextResend(seconds => seconds - 1), 1000);

    return () => window.clearTimeout(timerId);
  }, [secondsToNextResend]);

  const handleResend = () => {
    setValue('');
    setSecondsToNextResend(RESEND_COUNTDOWN_SECONDS);
  };

  return (
    <FieldCode
      codeLength={6}
      label='Код подтверждения'
      value={value}
      onChange={setValue}
      resendCode={{ onResend: handleResend, secondsToNextResend }}
    />
  );
}

Props

Types

PropsFieldCodeProps
PropTypeDefaultRequiredDescription
cellClassNamestringnoCSS-класс ячейки кода
classNamestringnoCSS-класс компонента
codeLengthnumberyesКоличество цифр в коде (целое ≥ 1)
data-test-idstringno
disabledbooleannoПоле выключено
errorstringnoОшибка (приоритетнее `hint`; форсит `validationState=error`)
invalidCodestringnoСообщение при неверном коде, если не передан свой `error`
labelstringnoЗаголовок
onChange((code: string) => void)noКолбек изменения значения
onComplete((code: string) => void)noКолбек ввода всех символов кода
resendCodeResendCodePropsnoКомпонент отправки нового кода
showEmptyCharsbooleannoПодсветить пустые символы кода
size"l" | "m" | "s"noРазмер
spacingnumber[]noПозиции, после которых нужно вставить пробел (индексы символов, после которых будет разрыв)
stretchCellsbooleannoРастягивать ячейки на всю доступную ширину; иначе фиксированная ширина по `size`
valuestringnoЗначение кода

Types

FieldCodeProps

Адаптивность

Раскладка читается из AdaptiveProvider (@cloud-ru/ds-adaptive); отдельного пропа layoutType нет. На mobile компонент не переносит фокус автоматически (ни при монтировании, ни при resetCode) — чтобы экранная клавиатура не открывалась без действия пользователя. Размер на mobile не меняется — база m.

Storybook