Skip to content

Commit 858b3af

Browse files
committed
feat(OtpInput): add paste support and fix input bugs with wheel and arrow keys
This update enhances the OTP input component by allowing users to paste numeric codes directly into the fields, automatically extracting only digits. It also fixes issues where mouse wheel and arrow up/down keys could unintentionally change input values. These improvements ensure a faster and more reliable OTP entry experience.
1 parent ec27354 commit 858b3af

File tree

1 file changed

+39
-9
lines changed
  • src/Components/Overview/SidebarContent/Content/Inputs

1 file changed

+39
-9
lines changed

src/Components/Overview/SidebarContent/Content/Inputs/OtpInput.jsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useRef } from "react";
1+
import { useState, useRef } from "react";
22

33
// components
44
import OverviewFooter from "../../../../../Shared/OverviewFooter";
@@ -61,6 +61,21 @@ const OtpInput = () => {
6161
}
6262
};
6363

64+
const handleAutoNavigationPaste = (e, index) => {
65+
e.preventDefault();
66+
const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, length);
67+
const newOtp = [...autoNavigationInputs.current.map(input => input.value)];
68+
69+
for (let i = 0; i < pastedData.length && i < length; i++) {
70+
newOtp[i] = pastedData[i];
71+
autoNavigationInputs.current[i].value = pastedData[i];
72+
}
73+
onChange(newOtp.join(''));
74+
75+
const focusIndex = Math.min(pastedData.length, length - 1);
76+
autoNavigationInputs.current[focusIndex].focus();
77+
};
78+
6479
// for custom navigation
6580
const handleCustomNavigationInputChange = (e, index) => {
6681
const { value } = e.target;
@@ -83,7 +98,6 @@ const OtpInput = () => {
8398
}
8499
}
85100

86-
87101
return (
88102
<>
89103
<aside className="flex items-start justify-between gap-6 w-full 640px:pl-[2.5rem] px-6 640px:px-10">
@@ -105,7 +119,7 @@ const OtpInput = () => {
105119
ref={(el) => (autoNavigationInputs.current[index] = el)}
106120
className='p-3 text-center dark:bg-transparent dark:border-slate-700 dark:text-[#abc2d3] dark:placeholder:text-slate-500 border border-[#bcbcbc] rounded-md outline-none focus:border-primary'
107121
placeholder='0'
108-
max="1"
122+
onWheel={(e) => e.target.blur()}
109123
onChange={(e) => handleCustomNavigationInputChange(e, index)}
110124
type='number'
111125
/>
@@ -154,7 +168,7 @@ const OtpInput = () => {
154168
ref={(el) => (navigationInputs.current[index] = el)}
155169
className="p-3 text-center dark:bg-transparent dark:border-slate-700 dark:text-[#abc2d3] dark:placeholder:text-slate-500 border border-[#bcbcbc] rounded-md outline-none focus:border-[#3B9DF8]"
156170
placeholder="0"
157-
max="1"
171+
onWheel={(e) => e.target.blur()}
158172
onChange={(e) => handleInputChange(e, index)}
159173
type="number"
160174
/>
@@ -174,8 +188,7 @@ export default OtpInput;
174188
<ContentHeader text={"Keyboard navigation"} id={"keyboard_navigation"}/>
175189
</div>
176190

177-
<ComponentDescription text='OTP input field with keyboard navigation, enabling users to move between digits using arrow keys
178-
for quick and efficient entry.'/>
191+
<ComponentDescription text='OTP input field with keyboard navigation, enabling users to move between digits using arrow keys and paste numeric codes (extracting only numbers) for quick and efficient entry.'/>
179192

180193
<ToggleTab code={autoNavigationCode} setCode={setAutoNavigationCode} setPreview={setAutoNavigationPreview} preview={autoNavigationPreview}/>
181194

@@ -190,9 +203,10 @@ export default OtpInput;
190203
ref={(el) => (autoNavigationInputs.current[index] = el)}
191204
className='p-3 text-center dark:bg-transparent dark:border-slate-700 dark:text-[#abc2d3] dark:placeholder:text-slate-500 border border-[#bcbcbc] rounded-md outline-none focus:border-primary'
192205
placeholder='0'
193-
max="1"
206+
onWheel={(e) => e.target.blur()}
194207
onChange={(e) => handleAutoNavigationInputChange(e, index)}
195208
onKeyDown={(e) => handleAutoNavigationKeydown(e, index)}
209+
onPaste={(e) => handleAutoNavigationPaste(e, index)}
196210
type='number'
197211
/>
198212
))
@@ -236,6 +250,21 @@ const OtpInput = () => {
236250
}
237251
};
238252
253+
const handlePaste = (e, index) => {
254+
e.preventDefault();
255+
const pastedData = e.clipboardData.getData("text").replace(/[^0-9]/g, "").slice(0, length);
256+
const newOtp = [...navigationInputs.current.map(input => input.value)];
257+
258+
for (let i = 0; i < pastedData.length && i < length; i++) {
259+
newOtp[i] = pastedData[i];
260+
navigationInputs.current[i].value = pastedData[i];
261+
}
262+
onChange(newOtp.join(""));
263+
264+
const focusIndex = Math.min(pastedData.length, length - 1);
265+
navigationInputs.current[focusIndex].focus();
266+
};
267+
239268
const handleKeydown = (e, index) => {
240269
if (e.key === "Backspace" && !navigationInputs.current[index].value && index > 0) {
241270
navigationInputs.current[index - 1].focus()
@@ -251,9 +280,10 @@ const OtpInput = () => {
251280
ref={(el) => (navigationInputs.current[index] = el)}
252281
className="p-3 text-center dark:bg-transparent dark:border-slate-700 dark:text-[#abc2d3] dark:placeholder:text-slate-500 border border-[#bcbcbc] rounded-md outline-none focus:border-[#3B9DF8]"
253282
placeholder="0"
254-
max="1"
283+
onWheel={(e) => e.target.blur()}
255284
onChange={(e) => handleInputChange(e, index)}
256285
onKeyDown={(e) => handleKeydown(e, index)}
286+
onPaste={(e) => handlePaste(e, index)}
257287
type="number"
258288
/>
259289
))
@@ -282,4 +312,4 @@ export default OtpInput;
282312
);
283313
};
284314

285-
export default OtpInput;
315+
export default OtpInput;

0 commit comments

Comments
 (0)