OTP Input
The otp input is optimized for entering a sequence of digits or letters. The input fields allow one character at a time. When the digit or letter is entered, focus transfers to the next input in the sequence, until every input is filled.
Features
Install
Install the component from your command line.
Anatomy
Import all parts and piece them together.
<script setup lang="ts">import * as otpInput from '@destyler/otp-input'import { normalizeProps, useMachine } from '@destyler/vue'import { computed, useId } from 'vue'
const [state, send] = useMachine(otpInput.machine({ id: useId(),}))
const api = computed(() => otpInput.connect(state.value, send, normalizeProps))</script>
<template> <div v-bind="api.getRootProps()"> <input v-bind="api.getInputProps({ index: 0 })"> <input v-bind="api.getInputProps({ index: 1 })"> <input v-bind="api.getInputProps({ index: 2 })"> </div> <button @click="api.clearValue" /></template>
import * as otpInput from '@destyler/otp-input'import { normalizeProps, useMachine } from '@destyler/react'import { useId, useMemo } from 'react'
export default function OtpInput() { const [state, send] = useMachine(otpInput.machine({ id: useId(), }))
const api = useMemo(() => otpInput.connect(state, send, normalizeProps), [state, send])
return ( <div {...api.getRootProps()} > <input {...api.getInputProps({ index:0 })}/> <input {...api.getInputProps({ index:1 })}/> <input {...api.getInputProps({ index:2 })}/> </div> <button onClick={api.clearValue}></button> )}
<script lang="ts"> import * as otpInput from "@destyler/otp-input"; import { normalizeProps, useMachine } from "@destyler/svelte";
const id = $props.id();
const [state, send] = useMachine(otpInput.machine({ id, }));
const api = $derived(otpInput.connect(state, send, normalizeProps));</script>
<div {...api.getRootProps()}> <input {...api.getInputProps({ index:0 })} /> <input {...api.getInputProps({ index:1 })} /> <input {...api.getInputProps({ index:2 })} /></div><button onclick={api.clearValue}></button>
import * as otpInput from '@destyler/otp-input'import { normalizeProps, useMachine } from '@destyler/solid'import { createMemo, createUniqueId } from 'solid-js'
export default function OtpInput() { const uniqueId = createUniqueId()
const [state, send] = useMachine(otpInput.machine({ id: uniqueId, }))
const api = createMemo(() => otpInput.connect(state, send, normalizeProps))
return ( <div {...api().getRootProps()}> <input {...api().getInputProps({ index: 0 })}/> <input {...api().getInputProps({ index: 1 })}/> <input {...api().getInputProps({ index: 2 })}/> </div> <button onClick={() => api().clearValue()}></button> )}
Setting a default value
To set the initial value of the otp input, pass the value
property to the destyler’s context.
const [state, send] = useMachine( otpInput.machine({ value: ["1", "2", ""], }),)
Changing the placeholder
To customize the default otp input placeholder (○) for each input,
pass the placeholder
prop and set it to your desired value.
const [state, send] = useMachine( otpInput.machine({ placeholder: "*", }),)
Blur on complete
By default, the last input maintains focus when filled and we invoke the onComplete
callback.
To blur the last input when the user completes the input, set the blurOnComplete: true
in the destyler’s context.
const [state, send] = useMachine( otpInput.machine({ blurOnComplete: true, }),)
Allowing alphanumeric values
By default, the otp input accepts only number values but you can choose between numeric
,
alphanumeric
and alphabetic
values. To change the input mode, pass the type
context property and set its value to alphanumeric
.
const [state, send] = useMachine( otpInput.machine({ type: "alphanumeric", }),)
Using OTP mode
To trigger smartphone OTP auto-suggestion, it is recommended to set the
autocomplete
attribute to “one-time-code”. The pin-input machine provides
support for this automatically when you set the otp
context property to true
.
const [state, send] = useMachine( otpInput.machine({ otp: true, }),)
Securing the text input
When collecting private or sensitive information using the otp input,
you might need to mask the value entered, similar to <input type="password"/>
.
Pass the mask
context property and set it to true
.
const [state, send] = useMachine( otpInput.machine({ mask: true, }),)
Listening for changes
The otp input machine invokes several callback functions when the user enters:
-
onValueChange
— Function invoked when the value is changed. -
onValueComplete
— Function invoked when all fields have been completed (by typing or pasting). -
onValueInvalid
— Function invoked when an invalid value is entered into the input. An invalid value is any value that doesn’t match the specified “type”.
const [state, send] = useMachine( otpInput.machine({ onValueChange(value) { // value => string[] console.log("value changed to:", value) }, onValueComplete(details) { // details => { value: string[], valueAsString: string } console.log("completed value:", details) }, onValueInvalid(details) { // details => { index: number, value: string } console.log("invalid value:", details) }, }),)
RTL support
The pin input machine supports RTL writing directions.
To set the dir
property in the destyler’s context.
When this attribute is set, we attach a dir
attribute to the root part.
const [state, send] = useMachine( otpInput.machine({ dir: "rtl", }),)
Styling guide
Earlier, we mentioned that each OTP Input part has a
data-part
attribute added to them to select and style them in the DOM.
Completed state
When all values have been filled, we attach a data-complete
attribute to the root and input parts.
[data-part="root"][data-complete] { /* styles for when all value has been filled */}
[data-part="input"][data-complete] { /* styles for when all value has been filled */}
Invalid state
When an invalid value is entered, we attach a data-invalid
attribute to the affected input part.
[data-part="input"][data-invalid] { /* styles for when the input is invalid */}
Disabled state
When the pin-input is disabled, we attach a data-disabled
attribute to the root and input parts.
[data-part="root"][data-disabled] { /* styles for when the input is disabled */}
[data-part="input"][data-invalid] { /* styles for when the input is disabled */}
Methods and Properties
Machine Context
The otp input machine exposes the following context properties:
string
string
string
Partial<{ root: string; hiddenInput: string; label: string; control: string; input(id: string): string; }>
boolean
string
boolean
boolean
boolean
boolean
boolean
string[]
"alphanumeric" | "numeric" | "alphabetic"
(details: ValueChangeDetails) => void
(details: ValueChangeDetails) => void
(details: ValueInvalidDetails) => void
boolean
boolean
boolean
IntlTranslations
"ltr" | "rtl"
string
() => ShadowRoot | Node | Document
Machine API
The otp input api
exposes the following methods:
string[]
string
boolean
(value: string[]) => void
() => void
(index: number, value: string) => void
() => void
Data Attributes
Root
data-scope
data-part
data-invalid
data-disabled
data-complete
data-readonly
Label
data-scope
data-part
data-invalid
data-disabled
data-complete
data-readonly
Input
data-scope
data-part
data-disabled
data-complete
data-invalid
Accessibility
Keyboard Interaction
ArrowLeft
ArrowRight
Backspace
Delete
Control + V