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-partattribute 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:
stringstringstringPartial<{ root: string; hiddenInput: string; label: string; control: string; input: (id: string) => string; }>booleanstringbooleanbooleanbooleanbooleanbooleanstring[]"alphanumeric" | "numeric" | "alphabetic"(details: ValueChangeDetails) => void(details: ValueChangeDetails) => void(details: ValueInvalidDetails) => voidbooleanbooleanbooleanIntlTranslations"ltr" | "rtl"string() => ShadowRoot | Node | DocumentMachine API
The otp input api exposes the following methods:
string[]stringboolean(value: string[]) => void() => void(index: number, value: string) => void() => voidData Attributes
Root
data-scopedata-partdata-invaliddata-disableddata-completedata-readonlyLabel
data-scopedata-partdata-invaliddata-disableddata-completedata-readonlyInput
data-scopedata-partdata-disableddata-completedata-invalidAccessibility
Keyboard Interaction
ArrowLeftArrowRightBackspaceDeleteControl + V