Through 6 divs, 6 rectangular input visual effects are formed. In fact, these are all on the bottom layer; the top layer is an input input box, and its color is set to transparent + absolute positioning.
jsx part
const [code, setCode] = useState('');
const [number] = useState([0, 1, 2, 3, 4, 5]);
const onChange = (e) => {
const v = e.target.value.replace(/\D/g, '');
setCode(v);
};
<div className={style.inputBox}>
{number.map((item, index) => (
<div className={style.codeItem} key={index}>
{code[index]?.replace(/[0-9]/g, '·')}
</div>
))}
<Input.Password
className={style.codeInput}
value={code}
maxLength={number.length}
onChange={onChange}
visibilityToggle={false}
readOnly={true}
autoComplete="new-password"
onFocus={(e) => e.target.removeAttribute('readonly')}
onBlur={(e) => e.target.setAttribute('readonly', 'true')}
/>
</div>
css part
.inputBox {
position: relative;
width: 336px;
margin: 0 auto;
display: flex;
justify-content: space-between;
font-weight: bold;
.codeItem {
width: 48px;
height: 48px;
line-height: 0.5;
text-align: center;
background: #ffffff;
border: 1px solid #ebecf0;
font-size: 80px;
}
.codeInput {
height: 48px;
position: absolute;
outline: none;
color: transparent !important;
caret-color: #ebecf0;
font-size: 28px;
padding: 0 16px;
letter-spacing: 48px;
width: 336px;
border: none;
background: none;
background-color: transparent !important;
-webkit-appearance: none;
&:focus {
border: none !important;
box-shadow: 0 0 0 0 #fff;
}
&::-webkit-input-safebox-button {
display: none;
}
}
}