← Components/Inputs & Forms

PinInput

pininput-1779394643106.tsx
'use client'
import { useState, useRef } from 'react'

export default function PinInput({ length = 4, masked = true, onComplete }) {
  const [pins, setPins] = useState(Array(length).fill(''))
  const refs = Array.from({ length }, (_, i) => useRef(null))
  const [complete, setComplete] = useState(false)
  const handleChange = (i, val) => {
    const v = val.replace(/[^0-9]/g,'').slice(-1)
    const next = [...pins]; next[i] = v; setPins(next)
    if (v && i < length-1) refs[i+1].current?.focus()
    if (next.every(p=>p)) { setComplete(true); onComplete?.(next.join('')) }
    else setComplete(false)
  }
  const handleKey = (i, e) => { if (e.key==='Backspace'&&!pins[i]&&i>0) refs[i-1].current?.focus() }
  if (complete) return (
    <div style={{ textAlign:'center', padding:'20px' }}>
      <div style={{ fontSize:'40px', marginBottom:'8px' }}>🔓</div>
      <div style={{ fontWeight:700, color:'#10b981' }}>PIN accepted!</div>
      <button onClick={()=>{setPins(Array(length).fill(''));setComplete(false)}} style={{ marginTop:'10px', background:'none', border:'1px solid #e2e8f0', borderRadius:'8px', padding:'6px 14px', cursor:'pointer', fontSize:'12px' }}>Reset</button>
    </div>
  )
  return (
    <div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:'16px' }}>
      <div style={{ fontSize:'13px', color:'#64748b', fontWeight:500 }}>Enter your {length}-digit PIN</div>
      <div style={{ display:'flex', gap:'10px' }}>
        {pins.map((p, i) => (
          <input key={i} ref={refs[i]} type={masked?'password':'text'} value={p} maxLength={1}
            onChange={e=>handleChange(i,e.target.value)} onKeyDown={e=>handleKey(i,e)}
            inputMode="numeric"
            style={{
              width:'52px', height:'60px', textAlign:'center', fontSize:'24px', fontWeight:700,
              border:'2px solid '+(p?'#6d28d9':'#e2e8f0'), borderRadius:'12px', outline:'none',
              background:p?'#faf5ff':'#fff', color:'#1e293b', transition:'all 0.15s',
            }}
          />
        ))}
      </div>
    </div>
  )
}

Component info

CategoryInputs & Forms
Frameworkreact
TierFREE
Views0
Copies0

About

PIN code input with masked characters and auto-submit

More from Inputs & Forms

'use client';

import { useState, useEffect } from 'react';

interface Tag {
  id: number;
  name: string;
}

const TagInput = () => {
  const [tags, setTags] = useState<Tag[]>([]);
  const [inputValue, setInputValue] = useState('');
  const [suggest
TagInput
Inputs & Forms
'use client';

import React, { useState } from 'react';

interface File {
  name: string;
  size: number;
  progress: number;
}

const FileUpload = () => {
  const [dragOver, setDragOver] = useState(false);
  const [files, setFiles] = useState<File[]
FileUpload
Inputs & Forms
import React, { useState } from 'react';

const OTPInput = () => {
  const [otp, setOtp] = useState(new Array(6).fill(''));
  const [activeIndex, setActiveIndex] = useState(0);

  const handleChange = (e, index) => {
    const value = e.target.value;
OTPInput
Inputs & Forms
'use client';

import React, { useState } from 'react';

interface RangeSliderProps {
  min: number;
  max: number;
  defaultValue: [number, number];
}

const RangeSlider: React.FC<RangeSliderProps> = ({ min, max, defaultValue }) => {
  const [minVal
RangeSlider
Inputs & Forms