Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ input::placeholder {
<td>false</td>
<td>Disables all the input fields.</td>
</tr>
<tr>
<td>paste-filter</td>
<td>boolean</td>
<td>false</td>
<td>false</td>
<td>When enabled, filters out invalid characters during paste operations instead of rejecting the entire paste. For "number" input type, only numeric characters are kept. For "letter-numeric" type, only alphanumeric characters are kept.</td>
</tr>
</table>

## 🤺 Methods
Expand Down
44 changes: 34 additions & 10 deletions src/components/vue3-otp-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Props = {
placeholder?: string[];
isDisabled?: boolean;
shouldFocusOrder?: boolean;
pasteFilter?: boolean;
};

const props = withDefaults(defineProps<Props>(), {
Expand All @@ -40,6 +41,7 @@ const props = withDefaults(defineProps<Props>(), {
isDisabled: false,
placeholder: () => [],
conditionalClass: () => [],
pasteFilter: false,
});

const emit = defineEmits<{
Expand Down Expand Up @@ -112,20 +114,42 @@ const changeCodeAtFocus = (value: number | string) => {
// Handle pasted OTP
const handleOnPaste = (event: any) => {
event.preventDefault();
const pastedData = event.clipboardData
let pastedData = event.clipboardData
.getData("text/plain")
.slice(0, props.numInputs - activeInput.value)
.split("");
if (props.inputType === "number" && !pastedData.join("").match(/^\d+$/)) {
return "Invalid pasted data";
}

if (
props.inputType === "letter-numeric" &&
!pastedData.join("").match(/^\w+$/)
) {
return "Invalid pasted data";
if (props.pasteFilter) {
// Filter characters based on input type when pasteFilter is enabled
if (props.inputType === "number") {
pastedData = pastedData.filter((char: string) => /^\d$/.test(char));
} else if (props.inputType === "letter-numeric") {
pastedData = pastedData.filter((char: string) => /^\w$/.test(char));
}

// If no valid characters remain after filtering, return early
if (pastedData.length === 0) {
return "No valid characters to paste";
}

// Apply length limit after filtering
pastedData = pastedData.slice(0, props.numInputs - activeInput.value);
} else {
// Apply length limit before validation for original behavior
pastedData = pastedData.slice(0, props.numInputs - activeInput.value);

// Original validation behavior when pasteFilter is disabled
if (props.inputType === "number" && !pastedData.join("").match(/^\d+$/)) {
return "Invalid pasted data";
}

if (
props.inputType === "letter-numeric" &&
!pastedData.join("").match(/^\w+$/)
) {
return "Invalid pasted data";
}
}

// Paste data from focused input onwards
const currentCharsInOtp = otp.value.slice(0, activeInput.value);
const combinedWithPastedData = currentCharsInOtp.concat(pastedData);
Expand Down