Skip to content

Instantly share code, notes, and snippets.

@thhmoc67
Created January 7, 2021 10:03
Show Gist options
  • Save thhmoc67/f6e4a32abd45ec1b692b46257dd2989b to your computer and use it in GitHub Desktop.
Save thhmoc67/f6e4a32abd45ec1b692b46257dd2989b to your computer and use it in GitHub Desktop.
OTP component
import React from 'react'
import './styles.scss'
import { elem } from '_helpers/css'
/**
* @param {length} number - Default value is 4
* @param {error} string - Default value is none
* @param {placeholder} string - Default value is none
* @param {onChange} function - Default value is none
*/
class InputOTP extends React.Component {
state = {
value: ['', '', '', '', '', '', '', '', ''],
currentKey: false
}
componentDidMount() {
elem(`otp${0}`) && elem(`otp${0}`).focus() // when component shows up, first input is focussed
}
onChange = ({ index, event }) => {
const key = event.key
const targetValue = event.target.value
if (targetValue === '') {
this.changeValue(targetValue, index)
} else if (targetValue < 10 && targetValue !== ' ' && !isNaN(targetValue)) {
this.changeValue(targetValue, index)
}
}
changeValue = (value, index) => {
let newArr = this.state.value
newArr[index] = value
this.setState({ value: newArr }, () => this.changeIndex(index, newArr))
}
changeIndex = (index, newArr) => {
const currentElement = elem(`otp${index}`)
const nextElement = elem(`otp${index + 1}`)
const prvElement = elem(`otp${index - 1}`)
if (currentElement.value === '') {
} else if (
currentElement.value &&
nextElement &&
nextElement.value === ''
) {
nextElement.focus()
}
this.blur(newArr.join(''))
}
blur = (value) => {
this.props.onChange(value)
}
onKeyDown = ({ index, event }) => {
const currentElement = elem(`otp${index}`)
const nextElement = elem(`otp${index + 1}`)
const prvElement = elem(`otp${index - 1}`)
const key = event.key
switch (key) {
case 'Backspace':
if (prvElement && currentElement.value === '') {
prvElement && prvElement.focus()
} else {
}
break
case 'ArrowRight':
this.timeout(nextElement)
this.setState({ currentKey: false })
break
case 'ArrowLeft':
this.timeout(prvElement)
this.setState({ currentKey: false })
break
case ' ':
break
case 'ArrowUp':
case 'ArrowDown':
event.preventDefault()
break
default:
break
}
}
timeout = (element) => {
element &&
setTimeout(() => {
const x = element.value
element.value = ''
element.value = x
element.focus()
}, 1)
}
render() {
const { length = 4, error, placeholder } = this.props
let input = []
for (let i = 0; i < length; i++) {
input.push(
<input
type="number"
id={`otp${i}`}
key={`otp${i}`}
className={`input ${error ? 'errorBorder' : ''}`}
maxLength={1}
onChange={(event) => this.onChange({ index: i, event })}
value={this.state.value[i]}
// onKeyUp={event => this.onKeyUp({ index: i, event })}
onKeyDown={(event) => this.onKeyDown({ index: i, event })}
placeholder={placeholder || ''}
// placeholder={placeholder || '⬤'}
autoComplete={'off'}
/>
)
}
return (
<div className="InputOTP">
<div className="inputs">{input}</div>
{error && <div className="error">{error}</div>}
</div>
)
}
}
export default InputOTP
// @import "~scss/base/globals";
.InputOTP {
width: 100%;
.error {
padding-left: 2px;
font-size: 9px;
color: #cc001a;
}
.input {
width: 20px;
outline: 0;
border: 0;
border: 1px solid gray;
padding: 8px 0px 10px 0px;
width: 38px;
background-position: bottom;
background-size: 50px 1px;
background-repeat: repeat-x;
background-position-x: 35px;
margin: 5px;
display: inline-block;
// padding: 0 0 10px 0;
text-align: center;
}
.input:focus {
outline: none;
border: 0;
background-image: null;
border: 1px solid black;
}
.input::-webkit-input-placeholder {
/* Edge */
color: rgba(0, 0, 0, 0.137);
font-size: 10px;
}
.input:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: rgba(0, 0, 0, 0.137);
font-size: 10px;
}
.input::placeholder {
color: rgba(0, 0, 0, 0.137);
font-size: 10px;
line-height: normal;
}
input[type='number']::-webkit-outer-spin-button,
input[type='number']::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment