Skip to content

Instantly share code, notes, and snippets.

@keval666
Forked from schriker/OTPInput.tsx
Created July 26, 2024 14:47
Show Gist options
  • Save keval666/c32c30678da52732dce68fefb8b58aa6 to your computer and use it in GitHub Desktop.
Save keval666/c32c30678da52732dce68fefb8b58aa6 to your computer and use it in GitHub Desktop.
Simple React Native One Time Password Input
import React, { useRef } from 'react'
import { NativeSyntheticEvent, TextInput, TextInputKeyPressEventData, View } from 'react-native'
import { useStyles } from 'lib/hooks'
import { createStyles } from 'lib/styles'
import { Nullable } from 'lib/types'
type OTPInputProps = {
length: number,
value: Array<string>,
disabled: boolean,
onChange(value: Array<string>): void
}
export const OTPInput: React.FunctionComponent<OTPInputProps> = ({
length,
disabled,
value,
onChange
}) => {
const { styles } = useStyles(stylesheet)
const inputRefs = useRef<Array<Nullable<TextInput>>>([])
const onChangeValue = (text: string, index: number) => {
const newValue = value.map((item, valueIndex) => {
if (valueIndex === index) {
return text
}
return item
})
onChange(newValue)
}
const handleChange = (text: string, index: number) => {
onChangeValue(text, index)
if (text.length !== 0) {
return inputRefs?.current[index + 1]?.focus()
}
return inputRefs?.current[index - 1]?.focus()
}
const handleBackspace = (event: NativeSyntheticEvent<TextInputKeyPressEventData>, index: number) => {
const { nativeEvent } = event
if (nativeEvent.key === 'Backspace') {
handleChange('', index)
}
}
return (
<View style={styles.container}>
{[...new Array(length)].map((item, index) => (
<TextInput
ref={ref => {
if (ref && !inputRefs.current.includes(ref)) {
inputRefs.current = [...inputRefs.current, ref]
}
}}
key={index}
maxLength={1}
contextMenuHidden
selectTextOnFocus
editable={!disabled}
style={styles.input}
keyboardType="decimal-pad"
testID={`OTPInput-${index}`}
onChangeText={text => handleChange(text, index)}
onKeyPress={event => handleBackspace(event, index)}
/>
))}
</View>
)
}
const stylesheet = createStyles(template => ({
container: {
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between'
},
input: {
fontSize: 24,
color: template.typography.regular,
textAlign: 'center',
width: 45,
height: 55,
backgroundColor: template.input.background,
borderRadius: template.input.borderRadius,
...template.ui.createShadow()
}
}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment