Hero Ui

HeroUI Input OTP

Forms 3

About

HeroUI v3 InputOTP — segmented one-time-password input: digit counts, patterns, disabled, controlled, validation, on-complete, form integration, variants and on-surface.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds HeroUI Input OTP to your project and fits it to your theme.

Code

How HeroUI Input OTP is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client"

import { InputOTP } from "@/components/ui/heroui-input-otp"
import { Button, Description, Form, Label, Link, Spinner } from "@heroui/react"
import React from "react"

export default function FormExample() {
  const [value, setValue] = React.useState("")
  const [error, setError] = React.useState("")
  const [isSubmitting, setIsSubmitting] = React.useState(false)

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    setError("")

    if (value.length !== 6) {
      setError("Please enter all 6 digits")

      return
    }

    setIsSubmitting(true)

    // Simulate API call
    setTimeout(() => {
      if (value === "123456") {
        console.log("Code verified successfully!")
        setValue("")
      } else {
        setError("Invalid code. Please try again.")
      }
      setIsSubmitting(false)
    }, 1500)
  }

  return (
    <Form className="flex w-[280px] flex-col gap-4" onSubmit={handleSubmit}>
      <div className="flex flex-col gap-2">
        <Label>Two-factor authentication</Label>
        <Description>Enter the 6-digit code from your authenticator app</Description>
        <InputOTP
          isInvalid={!!error}
          maxLength={6}
          value={value}
          onChange={(val) => {
            setValue(val)
            setError("")
          }}
        >
          <InputOTP.Group>
            <InputOTP.Slot index={0} />
            <InputOTP.Slot index={1} />
            <InputOTP.Slot index={2} />
          </InputOTP.Group>
          <InputOTP.Separator />
          <InputOTP.Group>
            <InputOTP.Slot index={3} />
            <InputOTP.Slot index={4} />
            <InputOTP.Slot index={5} />
          </InputOTP.Group>
        </InputOTP>
        <span className="field-error" data-visible={!!error} id="code-error">
          {error}
        </span>
      </div>
      <Button
        className="w-full"
        isDisabled={value.length !== 6}
        isPending={isSubmitting}
        type="submit"
        variant="primary"
      >
        {isSubmitting ? (
          <>
            <Spinner color="current" size="sm" />
            Verifying...
          </>
        ) : (
          "Verify"
        )}
      </Button>
      <div className="flex items-center justify-center gap-1">
        <p className="text-sm text-muted-foreground">Having trouble?</p>
        <Link className="text-sm text-foreground underline" href="#">
          Use backup code
        </Link>
      </div>
    </Form>
  )
}

Dependencies

More by Hero Ui

View all
  • DatePicker

    DatePicker

    466
  • Chip

    Chip

    440
  •  The Pagination

    The Pagination

    361
  • HeroUI Color Picker

    HeroUI Color Picker

    105
  • Skeleton

    Skeleton

    104
  • HeroUI Table

    HeroUI Table

    98
  • HeroUI Disclosure Group

    HeroUI Disclosure Group

    94
  • HeroUI AlertDialog

    HeroUI AlertDialog

    79

More in Forms

View all
  • Login 1

    Login 1

    52
  • Premium Auth

    Premium Auth

    491
  • Contact Card

    Contact Card

    1K
  • Form

    Form

    136
  • Login 2

    Login 2

    7
  • Login Form

    Login Form

    6
  • Authentication Card

    Authentication Card

    45
  • Card Studio

    Card Studio

    41