diff --git a/README.md b/README.md
index 6931cd7e..09a9a4d5 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,8 @@ A fully customizable, one-time password input component for the web built with R

[Live Demo](https://devfolioco.github.io/react-otp-input)
-
## Installation
@@ -24,6 +25,7 @@ npm install --save react-otp-input
```
### Still using v2?
+
No problem! You can find the documentation for v2 [here](https://github.com/devfolioco/react-otp-input/tree/v2.4.0)
#### Basic usage:
@@ -73,6 +75,13 @@ export default function App() {
The function will get two arguments: inputProps
and index
. inputProps
is an object that contains all the props that should be passed to the input being rendered (Overriding these props is not recommended because it might lead to some unexpected behaviour). index
is the index of the input being rendered.
+
+ onFocus |
+ function |
+ false |
+ none |
+ Called when OTP has received focus. The index of the input gaining focus is passed as the first argument |
+
onChange |
function |
@@ -96,6 +105,13 @@ const handlePaste: React.ClipboardEventHandler = (event) => {
+
+ onBlur |
+ function |
+ false |
+ none |
+ Called when OTP has lost focus. |
+
value |
string / number |
@@ -155,7 +171,9 @@ const handlePaste: React.ClipboardEventHandler = (event) => {
### ⚠️ Warning
+
Do not override the following props on the input component that you return from the `renderInput` prop. Doing so might lead to unexpected behaviour.
+
- `ref`
- `value`
- `onChange`
diff --git a/example/src/App.tsx b/example/src/App.tsx
index b08cce12..5620c983 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -110,7 +110,9 @@ function App() {
console.log(`OTP: Input #${index + 1} has gained focus!`)}
onChange={handleOTPChange}
+ onBlur={(index) => console.log(`OTP: Input #${index + 1} has lost focus!`)}
renderSeparator={{separator}}
value={otp}
placeholder={placeholder}
diff --git a/src/index.tsx b/src/index.tsx
index 3afd218a..8144f481 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -29,10 +29,14 @@ interface OTPInputProps {
value?: string;
/** Number of OTP inputs to be rendered */
numInputs?: number;
+ /** Callback to be called when the OTP has received focued */
+ onFocus?: (index: number) => void;
/** Callback to be called when the OTP value changes */
onChange: (otp: string) => void;
/** Callback to be called when pasting content into the component */
onPaste?: (event: React.ClipboardEvent) => void;
+ /** Callback to be called when the OTP has lost focus */
+ onBlur?: (index: number) => void;
/** Function to render the input */
renderInput: (inputProps: InputProps, index: number) => React.ReactNode;
/** Whether the first input should be auto focused */
@@ -56,8 +60,10 @@ const isStyleObject = (obj: unknown) => typeof obj === 'object' && obj !== null;
const OTPInput = ({
value = '',
numInputs = 4,
+ onFocus,
onChange,
onPaste,
+ onBlur,
renderInput,
shouldAutoFocus = false,
inputType = 'text',
@@ -145,10 +151,17 @@ const OTPInput = ({
const handleFocus = (event: React.FocusEvent) => (index: number) => {
setActiveInput(index);
event.target.select();
+
+ if (!inputRefs.current.includes(event.relatedTarget as HTMLInputElement)) {
+ onFocus?.(index);
+ }
};
- const handleBlur = () => {
+ const handleBlur = (event: React.FocusEvent) => (index: number) => {
setActiveInput(activeInput - 1);
+ if (!inputRefs.current.includes(event.relatedTarget as HTMLInputElement)) {
+ onBlur?.(index);
+ }
};
const handleKeyDown = (event: React.KeyboardEvent) => {
@@ -247,7 +260,7 @@ const OTPInput = ({
ref: (element) => (inputRefs.current[index] = element),
onChange: handleChange,
onFocus: (event) => handleFocus(event)(index),
- onBlur: handleBlur,
+ onBlur: (event) => handleBlur(event)(index),
onKeyDown: handleKeyDown,
onPaste: handlePaste,
autoComplete: 'off',