Preview Updated 2026-05-10

OtpInput

One-time password input cells — auto-advance to the next cell, Backspace, and full-string paste distribution.

Basic usage

length sets the number of cells. After typing, focus auto-advances; pasting a full string distributes characters across the remaining cells.

背景

当前值:(空)

src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const code = ref('');
</script>
<template>
  <div style="display: flex; flex-direction: column; gap: 8px;">
    <CfOtpInput v-model="code" :length="6" />
    <p style="margin: 0; font-size: 12px; color: var(--fg-3);">
      当前值:<code>{{ code || '(空)' }}</code>
    </p>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const code = ref('');
</script>
<template>
  <div style="display: flex; flex-direction: column; gap: 8px;">
    <CfOtpInput v-model="code" :length="6" />
    <p style="margin: 0; font-size: 12px; color: var(--fg-3);">
      当前值:<code>{{ code || '(空)' }}</code>
    </p>
  </div>
</template>
import { useState } from 'react';
import { CfOtpInput } from '@chufix-design/react';

export default function Demo() {
  const [code, setCode] = useState('');
  return (
    <>
      <CfOtpInput value={code} onChange={setCode} length={6} />
    </>
  );
}

Length

length is any integer — 4-digit PIN, 6-digit OTP (default), 8-digit long code.

背景
length = 4 (PIN)
length = 6(默认 OTP)
length = 8(更长验证码)
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const a = ref('');
const b = ref('');
const c = ref('');
</script>
<template>
  <div class="demo-stack">
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">length = 4 (PIN)</div>
      <CfOtpInput v-model="a" :length="4" />
    </div>
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">length = 6(默认 OTP)</div>
      <CfOtpInput v-model="b" :length="6" />
    </div>
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">length = 8(更长验证码)</div>
      <CfOtpInput v-model="c" :length="8" />
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const a = ref('');
const b = ref('');
const c = ref('');
</script>
<template>
  <div class="demo-stack">
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">length = 4 (PIN)</div>
      <CfOtpInput v-model="a" :length="4" />
    </div>
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">length = 6(默认 OTP)</div>
      <CfOtpInput v-model="b" :length="6" />
    </div>
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">length = 8(更长验证码)</div>
      <CfOtpInput v-model="c" :length="8" />
    </div>
  </div>
</template>
import { useState } from 'react';
import { CfOtpInput } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('');
  const [b, setB] = useState('');
  const [c, setC] = useState('');
  return (
    <>
      <CfOtpInput value={a} onChange={setA} length={4} />
      <CfOtpInput value={b} onChange={setB} length={6} />
      <CfOtpInput value={c} onChange={setC} length={8} />
    </>
  );
}

Character set

typenumeric (default, 0–9 only) / alphanumeric (letters + digits). Characters not in the set are stripped on paste.

背景
type = numeric(默认)— 仅 0–9
type = alphanumeric — 字母 + 数字
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const a = ref('');
const b = ref('');
</script>
<template>
  <div class="demo-stack">
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">type = numeric(默认)— 仅 0–9</div>
      <CfOtpInput v-model="a" :length="6" type="numeric" />
    </div>
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">type = alphanumeric — 字母 + 数字</div>
      <CfOtpInput v-model="b" :length="6" type="alphanumeric" />
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const a = ref('');
const b = ref('');
</script>
<template>
  <div class="demo-stack">
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">type = numeric(默认)— 仅 0–9</div>
      <CfOtpInput v-model="a" :length="6" type="numeric" />
    </div>
    <div>
      <div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">type = alphanumeric — 字母 + 数字</div>
      <CfOtpInput v-model="b" :length="6" type="alphanumeric" />
    </div>
  </div>
</template>
import { useState } from 'react';
import { CfOtpInput } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('');
  const [b, setB] = useState('');
  return (
    <>
      <CfOtpInput value={a} onChange={setA} length={6} type="numeric" />
      <CfOtpInput value={b} onChange={setB} length={6} type="alphanumeric" />
    </>
  );
}

Separator + autoFocus + complete

separatorAt inserts a separator after the Nth cell (visual grouping; commonly 3 / 4). autoFocus focuses the first cell on mount. When all cells are filled, complete / onComplete fires — handy for submitting the code immediately.

背景

当前值:(空)

src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const code = ref('');
const completed = ref<string | null>(null);
</script>
<template>
  <div style="display: flex; flex-direction: column; gap: 8px;">
    <CfOtpInput
      v-model="code"
      :length="6"
      :separator-at="3"
      auto-focus
      @complete="(v) => completed = v"
    />
    <p style="margin: 0; font-size: 12px; color: var(--fg-3);">
      当前值:<code>{{ code || '(空)' }}</code>
      <template v-if="completed"> · onComplete 已触发:<code>{{ completed }}</code></template>
    </p>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const code = ref('');
const completed = ref<string | null>(null);
</script>
<template>
  <div style="display: flex; flex-direction: column; gap: 8px;">
    <CfOtpInput
      v-model="code"
      :length="6"
      :separator-at="3"
      auto-focus
      @complete="(v) => completed = v"
    />
    <p style="margin: 0; font-size: 12px; color: var(--fg-3);">
      当前值:<code>{{ code || '(空)' }}</code>
      <template v-if="completed"> · onComplete 已触发:<code>{{ completed }}</code></template>
    </p>
  </div>
</template>
import { useState } from 'react';
import { CfOtpInput } from '@chufix-design/react';

export default function Demo() {
  const [code, setCode] = useState('');
  return (
    <>
      <CfOtpInput
      value={code}
      onChange={setCode}
      length={6}
      separatorAt={3}
      autoFocus
      onComplete={setCompleted}
      />
    </>
  );
}

Three sizes

sizesm compact, md default, lg mobile-friendly.

背景
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const a = ref('');
const b = ref('');
const c = ref('');
</script>
<template>
  <div class="demo-stack">
    <CfOtpInput v-model="a" :length="6" size="sm" />
    <CfOtpInput v-model="b" :length="6" size="md" />
    <CfOtpInput v-model="c" :length="6" size="lg" />
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfOtpInput } from '@chufix-design/vue';

const a = ref('');
const b = ref('');
const c = ref('');
</script>
<template>
  <div class="demo-stack">
    <CfOtpInput v-model="a" :length="6" size="sm" />
    <CfOtpInput v-model="b" :length="6" size="md" />
    <CfOtpInput v-model="c" :length="6" size="lg" />
  </div>
</template>
import { useState } from 'react';
import { CfOtpInput } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('');
  const [b, setB] = useState('');
  const [c, setC] = useState('');
  return (
    <>
      <CfOtpInput value={a} onChange={setA} length={6} size="sm" />
      <CfOtpInput value={b} onChange={setB} length={6} size="md" />
      <CfOtpInput value={c} onChange={setC} length={6} size="lg" />
    </>
  );
}

Keyboard interaction

KeyBehavior
Character keyWrites to the current cell and auto-advances
BackspaceClears the current cell if non-empty; otherwise moves back
/ Move focus between cells
PasteDistributes the string across remaining cells; extras are dropped

API · Props

PropTypeDefaultDescription
modelValue (Vue) / value (React)string''Current value
lengthnumber6Cell count
type'numeric' | 'alphanumeric''numeric'Allowed character set
size'sm' | 'md' | 'lg''md'Cell size
disabledbooleanfalseDisabled
autoFocusbooleanfalseFocus the first cell on mount
separatorAtnumberInsert a separator after the Nth cell (e.g. 3 after the 3rd)

API · Events

EventPayloadDescription
update:modelValue (Vue) / onChange (React)(value: string)Fires on any cell change
complete (Vue) / onComplete (React)(value: string)Fires when all cells are filled

反馈与讨论

OtpInput · Discussion

0
0 / 600
一键发送
正在加载评论...