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 [suggestTagInput
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 [minValRangeSlider
Inputs & Forms