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.
背景
当前值:(空)
<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(更长验证码)
<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
type — numeric (default, 0–9 only) / alphanumeric (letters + digits). Characters not in the set are stripped on paste.
背景
type = numeric(默认)— 仅 0–9
type = alphanumeric — 字母 + 数字
<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.
背景
当前值:(空)
<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
size — sm compact, md default, lg mobile-friendly.
背景
<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
| Key | Behavior |
|---|---|
| Character key | Writes to the current cell and auto-advances |
Backspace | Clears the current cell if non-empty; otherwise moves back |
← / → | Move focus between cells |
| Paste | Distributes the string across remaining cells; extras are dropped |
API · Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue (Vue) / value (React) | string | '' | Current value |
length | number | 6 | Cell count |
type | 'numeric' | 'alphanumeric' | 'numeric' | Allowed character set |
size | 'sm' | 'md' | 'lg' | 'md' | Cell size |
disabled | boolean | false | Disabled |
autoFocus | boolean | false | Focus the first cell on mount |
separatorAt | number | — | Insert a separator after the Nth cell (e.g. 3 after the 3rd) |
API · Events
| Event | Payload | Description |
|---|---|---|
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