ProComponents, templates & AI tooling
2.3k

InputOTP 一次性密码输入框

用于输入一次性验证码(OTP)的输入组件,支持分格、动画与校验。

导入

import { InputOTP } from 'heroui-native';

结构

<InputOTP>
  <InputOTP.Group>
    <InputOTP.Slot index={0} />
    <InputOTP.Slot index={1} />
  </InputOTP.Group>
  <InputOTP.Separator />
  <InputOTP.Group>
    <InputOTP.Slot index={2}>
      <InputOTP.SlotPlaceholder />
      <InputOTP.SlotValue />
      <InputOTP.SlotCaret />
    </InputOTP.Slot>
  </InputOTP.Group>
</InputOTP>
  • InputOTP:根容器,管理 OTP 状态与文本变更,并为子组件提供上下文;处理焦点、校验与字符输入。
  • InputOTP.Group:将多个格子编组;用于视觉分组(例如每 3 位一组)。
  • InputOTP.Slot:单个字符格;index 须在 OTP 序列中唯一且与位置对应。未提供子节点时,默认渲染 SlotPlaceholderSlotValueSlotCaret
  • InputOTP.SlotPlaceholder:空位时显示的占位字符;Slot 无子节点时默认使用。
  • InputOTP.SlotValue:显示已输入字符并带动画;Slot 无子节点时默认使用。
  • InputOTP.SlotCaret:动画光标,指示当前输入位置;置于 Slot 内以显示正在输入的位置。
  • InputOTP.Separator:分组之间的视觉分隔符。

用法

基础用法

创建 6 位 OTP,分两组并带分隔符。

<InputOTP maxLength={6} onComplete={(code) => console.log(code)}>
  <InputOTP.Group>
    <InputOTP.Slot index={0} />
    <InputOTP.Slot index={1} />
    <InputOTP.Slot index={2} />
  </InputOTP.Group>
  <InputOTP.Separator />
  <InputOTP.Group>
    <InputOTP.Slot index={3} />
    <InputOTP.Slot index={4} />
    <InputOTP.Slot index={5} />
  </InputOTP.Group>
</InputOTP>

四位 PIN

简单的 4 位数字 PIN。

<InputOTP maxLength={4} onComplete={(code) => console.log(code)}>
  <InputOTP.Slot index={0} />
  <InputOTP.Slot index={1} />
  <InputOTP.Slot index={2} />
  <InputOTP.Slot index={3} />
</InputOTP>

自定义占位

为每个格子位置提供自定义占位字符。

<InputOTP
  maxLength={6}
  placeholder="——————"
  onComplete={(code) => console.log(code)}
>
  <InputOTP.Group>
    {({ slots }) => (
      <>
        {slots.map((slot) => (
          <InputOTP.Slot key={slot.index} index={slot.index} />
        ))}
      </>
    )}
  </InputOTP.Group>
</InputOTP>

受控值

以编程方式控制 OTP 值。

const [value, setValue] = useState('');

<InputOTP value={value} onChange={setValue} maxLength={6}>
  <InputOTP.Group>
    <InputOTP.Slot index={0} />
    <InputOTP.Slot index={1} />
    <InputOTP.Slot index={2} />
  </InputOTP.Group>
  <InputOTP.Separator />
  <InputOTP.Group>
    <InputOTP.Slot index={3} />
    <InputOTP.Slot index={4} />
    <InputOTP.Slot index={5} />
  </InputOTP.Group>
</InputOTP>;

校验态

非法时展示校验错误样式。

<InputOTP value={value} onChange={setValue} maxLength={6} isInvalid={isInvalid}>
  <InputOTP.Group>
    <InputOTP.Slot index={0} />
    <InputOTP.Slot index={1} />
    <InputOTP.Slot index={2} />
  </InputOTP.Group>
  <InputOTP.Separator />
  <InputOTP.Group>
    <InputOTP.Slot index={3} />
    <InputOTP.Slot index={4} />
    <InputOTP.Slot index={5} />
  </InputOTP.Group>
</InputOTP>

输入模式(正则)

使用正则限制可输入字符。内置:REGEXP_ONLY_DIGITS(0–9)、REGEXP_ONLY_CHARS(a–z、A–Z)、REGEXP_ONLY_DIGITS_AND_CHARS(数字与字母)。

import { InputOTP, REGEXP_ONLY_CHARS } from 'heroui-native';

<InputOTP
  maxLength={6}
  pattern={REGEXP_ONLY_CHARS}
  inputMode="text"
  onComplete={(code) => console.log(code)}
>
  <InputOTP.Group>
    <InputOTP.Slot index={0} />
    <InputOTP.Slot index={1} />
    <InputOTP.Slot index={2} />
  </InputOTP.Group>
  <InputOTP.Separator />
  <InputOTP.Group>
    <InputOTP.Slot index={3} />
    <InputOTP.Slot index={4} />
    <InputOTP.Slot index={5} />
  </InputOTP.Group>
</InputOTP>;

自定义布局

Group 上使用渲染属性以自定义格子布局。

<InputOTP maxLength={6}>
  <InputOTP.Group>
    {({ slots, isFocused, isInvalid }) => (
      <>
        {slots.map((slot) => (
          <InputOTP.Slot
            key={slot.index}
            index={slot.index}
            className={cn('custom-class', slot.isActive && 'active-class')}
          >
            <InputOTP.SlotPlaceholder />
            <InputOTP.SlotValue />
            <InputOTP.SlotCaret />
          </InputOTP.Slot>
        ))}
      </>
    )}
  </InputOTP.Group>
</InputOTP>

在底部抽屉内

BottomSheet 中渲染 InputOTP 时,使用 useBottomSheetAwareHandlers 返回的 onFocus / onBlur 传给 InputOTP,以正确处理键盘避让。

import { InputOTP, useBottomSheetAwareHandlers } from 'heroui-native';

const BottomSheetOTPInput = () => {
  const { onFocus, onBlur } = useBottomSheetAwareHandlers();

  return (
    <InputOTP maxLength={6} onFocus={onFocus} onBlur={onBlur}>
      <InputOTP.Group>
        <InputOTP.Slot index={0} />
        <InputOTP.Slot index={1} />
        <InputOTP.Slot index={2} />
      </InputOTP.Group>
      <InputOTP.Separator />
      <InputOTP.Group>
        <InputOTP.Slot index={3} />
        <InputOTP.Slot index={4} />
        <InputOTP.Slot index={5} />
      </InputOTP.Group>
    </InputOTP>
  );
};

示例

import { InputOTP, Label, Description, type InputOTPRef } from 'heroui-native';
import { View } from 'react-native';
import { useRef } from 'react';

export default function InputOTPExample() {
  const ref = useRef<InputOTPRef>(null);

  const onComplete = (code: string) => {
    console.log('OTP completed:', code);
    setTimeout(() => {
      ref.current?.clear();
    }, 1000);
  };

  return (
    <View className="flex-1 px-5 items-center justify-center">
      <View>
        <Label>验证账户</Label>
        <Description className="mb-3">
          我们已向 a****@gmail.com 发送验证码
        </Description>
        <InputOTP ref={ref} maxLength={6} onComplete={onComplete}>
          <InputOTP.Group>
            <InputOTP.Slot index={0} />
            <InputOTP.Slot index={1} />
            <InputOTP.Slot index={2} />
          </InputOTP.Group>
          <InputOTP.Separator />
          <InputOTP.Group>
            <InputOTP.Slot index={3} />
            <InputOTP.Slot index={4} />
            <InputOTP.Slot index={5} />
          </InputOTP.Group>
        </InputOTP>
      </View>
    </View>
  );
}

更多示例见 GitHub 仓库

API 参考

InputOTP

proptypedefaultdescription
maxLengthnumber-OTP 最大长度(必填)
valuestring-受控值
defaultValuestring-非受控默认值
onChange(value: string) => void-值变化回调
onComplete(value: string) => void-所有格子填满时触发
isDisabledbooleanfalse是否禁用
isInvalidbooleanfalse是否处于非法状态
patternstring-允许字符的正则(如 REGEXP_ONLY_DIGITSREGEXP_ONLY_CHARS
inputModeTextInputProps['inputMode']'numeric'输入模式
placeholderstring-占位字符串;每个字符对应一个格子位置
placeholderTextColorstring-全部格子的占位文字颜色
placeholderTextClassNamestring-全部格子的占位文字 class
pasteTransformer(text: string) => string-粘贴内容转换(如去掉连字符);默认会移除非匹配字符
onFocus(e: FocusEvent) => void-聚焦回调
onBlur(e: BlurEvent) => void-失焦回调
textInputPropsOmit<TextInputProps, ...>-透传给底层 TextInput 的额外属性
childrenReact.ReactNode-子节点
classNamestring-根容器额外 class
stylePressableProps['style']-传给容器 Pressable 的样式
isBottomSheetAwarebooleantrueBottomSheet 内是否自动处理键盘相关状态;设为 false 可关闭
animation"disable-all" | undefinedundefined动画配置;"disable-all" 可禁用自身及子级全部动画

InputOTP.Group

proptypedefaultdescription
childrenReact.ReactNode | ((props: InputOTPGroupRenderProps) => React.ReactNode)-子节点,或接收格子数据与上下文的渲染函数
classNamestring-额外 class
...ViewPropsViewProps-支持全部标准 React Native View 属性

InputOTPGroupRenderProps

proptypedescription
slotsSlotData[]每个位置的格子数据数组
maxLengthnumberOTP 最大长度
valuestring当前 OTP 值
isFocusedboolean是否聚焦
isDisabledboolean是否禁用
isInvalidboolean是否非法

InputOTP.Slot

proptypedefaultdescription
indexnumber-格子下标(必填),须为 0maxLength - 1
childrenReact.ReactNode-自定义格子内容;未提供时默认为 SlotPlaceholderSlotValueSlotCaret
classNamestring-额外 class
styleViewStyle-额外样式
...ViewPropsViewProps-支持全部标准 React Native View 属性

InputOTP.SlotPlaceholder

proptypedefaultdescription
childrenstring-显示文本(可选,默认使用 slot.placeholderChar
classNamestring-额外 class
styleTextStyle-额外样式
...TextPropsTextProps-支持全部标准 React Native Text 属性

InputOTP.SlotValue

proptypedefaultdescription
childrenstring-显示文本(可选,默认使用 slot.char
classNamestring-额外 class
animationInputOTPSlotValueAnimation-SlotValue 动画配置
...TextPropsTextProps-支持全部标准 React Native Text 属性

InputOTPSlotValueAnimation

InputOTP.SlotValue 动画配置,可为:

  • false"disabled":禁用全部动画
  • trueundefined:使用默认动画
  • object:自定义动画配置
proptypedefaultdescription
state'disabled' | boolean-在自定义属性时用于禁用动画
wrapper.enteringEntryOrExitLayoutTypeFadeIn.duration(250)包裹层进入动画
wrapper.exitingEntryOrExitLayoutTypeFadeOut.duration(100)包裹层退出动画
text.enteringEntryOrExitLayoutTypeFlipInXDown.duration(250).easing(...)文本进入动画
text.exitingEntryOrExitLayoutTypeFlipOutXDown.duration(250).easing(...)文本退出动画

InputOTP.SlotCaret

proptypedefaultdescription
classNamestring-额外 class
styleViewStyle-额外样式
animationInputOTPSlotCaretAnimation-SlotCaret 动画配置
isAnimatedStyleActivebooleantrue是否启用 Reanimated 动画样式;为 false 时移除内置动画样式,可自行实现
pointerEvents'none' | 'auto' | ...'none'指针事件配置
...ViewPropsViewProps-支持全部标准 React Native View 属性

InputOTPSlotCaretAnimation

InputOTP.SlotCaret 动画配置,可为:

  • false"disabled":禁用全部动画
  • trueundefined:使用默认动画
  • object:自定义动画配置
proptypedefaultdescription
state'disabled' | boolean-在自定义属性时用于禁用动画
opacity.value[number, number][0, 1]透明度 [最小, 最大]
opacity.durationnumber500动画时长(毫秒)
height.value[number, number][16, 18]高度 [最小, 最大](像素)
height.durationnumber500动画时长(毫秒)

InputOTP.Separator

proptypedefaultdescription
classNamestring-额外 class
...ViewPropsViewProps-支持全部标准 React Native View 属性

Hooks

useInputOTP

读取 InputOTP 根上下文,须在 InputOTP 内使用。

const { value, maxLength, isFocused, isDisabled, isInvalid, slots } =
  useInputOTP();

useInputOTPSlot

读取 InputOTP.Slot 上下文,须在 InputOTP.Slot 内使用。

const { slot, isActive, isCaretVisible } = useInputOTPSlot();

本页目录