input-otp

repository·master·Indexed 25 days ago

https://github.com/guilhermerodz/input-otp

An accessible, unstyled, and fully featured one-time-password (OTP) component for React. It utilizes a single invisible text input to maintain native browser behaviors such as SMS autofill, screen reader support, and standard keyboard interactions while providing developers the flexibility to render custom UI for OTP slots via a render prop or the OTPInputContext.

Tokens
3K
Snippets
9
Records
19
Agent score
83%

What's inside input-otp

  1. Configure CRON_SECRET for Vercel deployments

    master

    The /api/refresh-stats route uses a CRON_SECRET to prevent unauthorized users from triggering cache invalidations and outbound requests to npm-stat.

    1. Generate a secret: Create a high-entropy string (at least 16 alphanumeric characters).
      openssl rand -hex 32
    2. Add to Vercel: Add the variable to your Vercel project settings under Settings → Environment Variables (scoped to Production), or via the CLI:
      vercel env add CRON_SECRET production
    3. Redeploy: Environment changes require a new deployment to take effect.

    Route Behavior Reference

    EnvironmentCRON_SECRETBehaviour
    LocalunsetOpen, so you can call it while developing
    LocalsetEnforced, same as production
    Productionunset503 CRON_SECRET is not configured
    Productionset401 unless the bearer token matches
    openssl rand -hex 32
  2. Adjust Cron schedule for Vercel Hobby plans

    master

    The default cron schedule is 0 0,12 * * * (twice daily). Because Vercel Hobby plans are limited to one cron trigger per day, you must modify vercel.json to use a daily schedule if you are on a Hobby plan:

    // vercel.json
    {
      "crons": [
        {
          "schedule": "0 0 * * *"
        }
      ]
    }
  3. Basic usage of OTPInput

    master

    To use OTPInput, specify the maxLength (number of slots) and provide a render function. The render function receives an object containing slots, which you can map over to draw your custom UI. Each slot provides the necessary state to render the character, placeholder, active status, and fake caret.

    'use client'
    import { OTPInput } from 'input-otp'
    
    export function VerificationCode() {
      return (
        <OTPInput
          maxLength={6}
          containerClassName="group flex items-center"
          render={({ slots }) => (
            <div className="flex">
              {slots.map((slot, idx) => (
                <Slot key={idx} {...slot} />
              ))}
            </div>
          )}
        />
      )
    }
  4. Reference: OTPInputProps

    master

    The OTPInput component accepts the following props:

    PropTypeDescription
    maxLengthnumberRequired. The number of slots.
    render(props: RenderProps) => React.ReactNodeFunction to render the slots.
    childrenReact.ReactNodeAlternative to render; allows composing via OTPInputContext.
    valuestringControlled value.
    onChange(newValue: string) => unknownCallback when value changes (returns the string, not an event).
    onComplete(value: string) => unknownFires once when the input reaches maxLength.
    patternstring | RegExpGates every change; no default.
    placeholderstringPer-slot placeholder characters.
    pasteTransformer(pasted: string) => stringFunction to transform pasted text.
    containerClassNamestringClass name for the visible wrapper.
    classNamestringClass name for the invisible real input.
    textAlign'left' | 'center' | 'right'Text alignment (default: 'left').
    inputMode'numeric' | 'text' | ...Input mode (default: 'numeric').
    pushPasswordManagerStrategy'increase-width' | 'none'Strategy for handling password manager badges.
    noScriptCSSFallbackstring | nullCSS for <noscript> fallback.
    noncestringFor CSP style-src on injected <style> tags.

    All standard <input> attributes (e.g., name, required, disabled, autoFocus, aria-*, data-*) are forwarded to the real input. The ref points to the real input.

  5. Reference: SlotProps

    master

    The SlotProps object is passed to the render function for each slot and contains the following properties:

    • char: string | null - The character in this slot.
    • placeholderChar: string | null - The character to show if the slot is empty.
    • isActive: boolean - Whether this slot is currently being edited.
    • hasFakeCaret: boolean - Whether to show the custom fake caret (the real caret is transparent).
  6. Build custom OTP UI with Slot components

    master

    The input-otp library does not render the individual cells of the OTP input. Instead, it provides the state (char, placeholderChar, isActive, and hasFakeCaret) to your custom components. You can use the following sub-components to build your own UI:

    • Slot: Represents a single visible cell. It receives props from input-otp to determine what to display and whether to show a fake caret.
    • SlotGroup: A wrapper used to group multiple Slot components together (e.g., for creating segmented inputs).
    • FakeCaret: A blinking bar component used to simulate a cursor, as the real input caret is typically made transparent in custom OTP implementations.
    • FakeDash: A decorative component used to create visual separators (like dashes) between SlotGroup instances.
  7. Use the render function with OTPInputProps

    master

    When providing a render function to the OTP input, you receive RenderProps which contains an array of SlotProps. This allows for complete control over how each character slot is displayed.

    interface SlotProps {
      isActive: boolean
      char: string | null
      placeholderChar: string | null
      hasFakeCaret: boolean
    }
    
    interface RenderProps {
      slots: SlotProps[]
      isFocused: boolean
      isHovering: boolean
    }
    
    type InputOTPRenderFn = (props: RenderProps) => React.ReactNode