InputLabel
Get Started
Introduction
Components
Accordion
Badge
Button
Card
Checkbox
Command
Dialog
Dropdown Menu
Input
Select
Switch
Table
Tabs
Toast
Tooltip
Forms
Controlled Input
Field Arrays
Submit
Validation

Input OTP

An accessible one-time password input component with copy-paste support.

4
6

#Installation

bunx --bun barefoot add input-otp

#Usage

1"use client"23import { createSignal } from "@barefootjs/dom"4import {5  InputOTP,6  InputOTPGroup,7  InputOTPSlot,8  InputOTPSeparator,9} from "@/components/ui/input-otp"1011function InputOTPDemo() {12  const [value, setValue] = createSignal("")1314  return (15    <InputOTP16      maxLength={6}17      pattern="digits-and-chars"18      value={value()}19      onValueChange={setValue}20    >21      <InputOTPGroup>22        <InputOTPSlot index={0} />23        <InputOTPSlot index={1} />24        <InputOTPSlot index={2} />25      </InputOTPGroup>26      <InputOTPSeparator />27      <InputOTPGroup>28        <InputOTPSlot index={3} />29        <InputOTPSlot index={4} />30        <InputOTPSlot index={5} />31      </InputOTPGroup>32    </InputOTP>33  )34}

#Examples

#Basic

1import {2  InputOTP,3  InputOTPGroup,4  InputOTPSlot,5} from "@/components/ui/input-otp"67export function InputOTPBasicDemo() {8  return (9    <InputOTP maxLength={4}>10      <InputOTPGroup>11        <InputOTPSlot index={0} />12        <InputOTPSlot index={1} />13        <InputOTPSlot index={2} />14        <InputOTPSlot index={3} />15      </InputOTPGroup>16    </InputOTP>17  )18}

#Pattern

Accepts letters and numbers.

1import {2  InputOTP,3  InputOTPGroup,4  InputOTPSlot,5  REGEXP_ONLY_DIGITS_AND_CHARS,6} from "@/components/ui/input-otp"78export function InputOTPPatternDemo() {9  return (10    <div className="space-y-2">11      <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}>12        <InputOTPGroup>13          <InputOTPSlot index={0} />14          <InputOTPSlot index={1} />15          <InputOTPSlot index={2} />16          <InputOTPSlot index={3} />17          <InputOTPSlot index={4} />18          <InputOTPSlot index={5} />19        </InputOTPGroup>20      </InputOTP>21      <p className="text-sm text-muted-foreground">22        Accepts letters and numbers.23      </p>24    </div>25  )26}

#Form

Verification Code

Enter the 6-digit code sent to your phone. Try 123456 to see success.

1"use client"23import { createSignal, createMemo, onCleanup } from "@barefootjs/dom"4import {5  InputOTP,6  InputOTPGroup,7  InputOTPSlot,8  InputOTPSeparator,9} from "@/components/ui/input-otp"1011export function InputOTPFormDemo() {12  const [value, setValue] = createSignal('')13  const [status, setStatus] = createSignal('idle')14  const [canResend, setCanResend] = createSignal(true)15  const [countdown, setCountdown] = createSignal(0)1617  const isComplete = createMemo(() => value().length === 6)1819  const handleSubmit = () => {20    if (!isComplete()) return21    setStatus('loading')22    setTimeout(() => {23      if (value() === '123456') {24        setStatus('success')25      } else {26        setStatus('error')27      }28    }, 1500)29  }3031  const handleResend = () => {32    if (!canResend()) return33    setCanResend(false)34    setCountdown(30)35    setValue('')36    setStatus('idle')3738    const timer = setInterval(() => {39      setCountdown(prev => {40        if (prev <= 1) {41          clearInterval(timer)42          setCanResend(true)43          return 044        }45        return prev - 146      })47    }, 1000)48    onCleanup(() => clearInterval(timer))49  }5051  return (52    <div className="space-y-4">53      <InputOTP maxLength={6} value={value()} onValueChange={setValue}54        disabled={status() === 'loading' || status() === 'success'}>55        <InputOTPGroup>56          <InputOTPSlot index={0} />57          <InputOTPSlot index={1} />58          <InputOTPSlot index={2} />59        </InputOTPGroup>60        <InputOTPSeparator />61        <InputOTPGroup>62          <InputOTPSlot index={3} />63          <InputOTPSlot index={4} />64          <InputOTPSlot index={5} />65        </InputOTPGroup>66      </InputOTP>67      <div className="flex items-center gap-3">68        <button disabled={!isComplete() || status() === 'loading'}69          onClick={handleSubmit}>70          {status() === 'loading' ? 'Verifying...' : 'Verify'}71        </button>72        <button disabled={!canResend()} onClick={handleResend}>73          {canResend() ? 'Resend code' : `Resend in ${countdown()}s`}74        </button>75      </div>76      {status() === 'success' && <p>Code verified successfully!</p>}77      {status() === 'error' && <p>Invalid code. Please try again.</p>}78    </div>79  )80}

#API Reference

PropTypeDefaultDescription
maxLengthnumber-The maximum number of characters. Determines how many slots to fill.
valuestring-The controlled value of the OTP input.
defaultValuestring''The default value for uncontrolled mode.
onValueChange(value: string) => void-Event handler called when the value changes.
onComplete(value: string) => void-Event handler called when all slots are filled.
patternRegExp | 'digits' | 'chars' | 'digits-and-chars''digits'Pattern to validate each character. Use a preset name ('digits', 'chars', 'digits-and-chars') or a RegExp.
disabledbooleanfalseWhether the input is disabled.