Create OTP Verification Form New UI Using Vanilla Js


 

In the ever-evolving landscape of web development, security remains a paramount concern. One effective way to bolster user authentication is by implementing One-Time Passwords (OTPs). In this article, we'll explore how to leverage the lightweight JavaScript library, OTP-Input, to seamlessly integrate OTP functionality into your web applications.

Understanding OTP-Input

OTP-Input simplifies the implementation of OTPs with its minimalist design and seamless integration. This library is written in Vanilla JavaScript, making it lightweight and versatile for a variety of web projects.

Getting Started

To get started, include the OTP-Input library in your project. You can either download it or use a CDN link. 

HTML CODE :

<!-------- Code by Codegyan -------->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>OTP Input</title>

        <link rel="preconnect" href="https://fonts.googleapis.com" />
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
        <link
            href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Lexend:wght@100;200;300;400;500;600;700;800;900&display=swap"
            rel="stylesheet"
        />
        <link rel="stylesheet" href="./otp-input.css" />
    </head>
    <body>
        <div class="main-content-container">
            <div class="text-container">
                <div class="font-h2-strong">OTP Input</div>
                <div class="font-text-large-1">Enter your one-time password</div>
            </div>

            <div id="otp-input" class="font-h2-strong">
                <input class="font-h2-strong" placeholder="_" type="number" step="1" min="0" max="9" autocomplete="no" pattern="\d*" />
                <input class="font-h2-strong" placeholder="_" type="number" step="1" min="0" max="9" autocomplete="no" pattern="\d*" />
                <input class="font-h2-strong" placeholder="_" type="number" step="1" min="0" max="9" autocomplete="no" pattern="\d*" />
                <input class="font-h2-strong" placeholder="_" type="number" step="1" min="0" max="9" autocomplete="no" pattern="\d*" />
                <input class="font-h2-strong" placeholder="_" type="number" step="1" min="0" max="9" autocomplete="no" pattern="\d*" />
                <input class="font-h2-strong" placeholder="_" type="number" step="1" min="0" max="9" autocomplete="no" pattern="\d*" />
                <input id="otp-value" placeholder="_" type="hidden" name="otp" />
            </div>

            <button id="submit">Submit</button>

            <!-- <button class="primary-button continue-button">Continue</button> -->
        </div>
        <script src="./otp-input.js"></script>
    </body>
</html>

CSS

While OTP-Input provides a basic styling, you can further customize the appearance to align with your application's design. Create a new css file named as otp-input.css.

body,
html {
    height: 100%;
    width: 100%;
    background-color: #faf9f6;
    display: flex;
}

.font-h2-strong {
    color: #141414;
    font-weight: 400;
    font-size: 24px;
    line-height: 31.68px;
    font-family: "Lexend", sans-serif;
}

.font-text-large-1 {
    color: #8f8f8f;
    font-weight: 400;
    font-size: 16px;
    line-height: 20px;
    font-family: "Inter", sans-serif;
}

.main-content-container {
    display: flex;
    flex-grow: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    row-gap: 32px;
}

.text-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    row-gap: 12px;
}

button {
    background-color: #497e76;
    padding: 10px 16px 10px 16px;
    border: none;
    border-radius: 4px;
    line-height: 20px;
    font-weight: 500;
    color: #ffffff;
    font-family: "Inter", sans-serif;
    width: 100%;
    max-width: 220px;
    font-size: 16px;
    cursor: pointer;
}

#otp-input {
    display: flex;
    column-gap: 8px;
}

#otp-input input {
    text-align: center;
    padding: 10px 8px 10px 8px;
    border: 1px solid #adadad;
    border-radius: 4px;
    outline: none;
    height: 64px;
    width: 50px;
}

#otp-input input:focus {
    border: 1px solid #497e76;
}

#otp-input input:focus::placeholder {
    color: transparent;
}

#otp-input input::-webkit-outer-spin-button,
#otp-input input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
#otp-input input[type="number"] {
    -moz-appearance: textfield; /* Firefox */
}

JavaScript

Create a new js file named as otp-input.js.

window.addEventListener("load", function () {
    // Get otp container
    const OTPContainer = document.querySelector("#otp-input");

    const OTPValueContainer = document.querySelector("#otp-value");

    const continueButton = document.querySelector("#submit");
    continueButton.addEventListener("click", (e) => {
        updateValue(inputs);
        alert(OTPValueContainer.value);
    });

    // Focus first input
    const firstInput = OTPContainer.querySelector("input");
    firstInput.focus();

    // OTP Logic

    const updateValue = (inputs) => {
        OTPValueContainer.value = Array.from(inputs).reduce((acc, curInput) => acc.concat(curInput.value ? curInput.value : "*"), "");
    };

    const isValidInput = (inputValue) => {
        return Number(inputValue) === 0 && inputValue !== "0" ? false : true;
    };

    const setInputValue = (inputElement, inputValue) => {
        inputElement.value = inputValue;
    };

    const resetInput = (inputElement) => {
        setInputValue(inputElement, "");
    };

    const focusNext = (inputs, curIndex) => {
        const nextElement = curIndex < inputs.length - 1 ? inputs[curIndex + 1] : inputs[curIndex];

        nextElement.focus();
        nextElement.select();
    };

    const focusPrev = (inputs, curIndex) => {
        const prevElement = curIndex > 0 ? inputs[curIndex - 1] : inputs[curIndex];

        prevElement.focus();
        prevElement.select();
    };

    const focusIndex = (inputs, index) => {
        const element = index < inputs.length - 1 ? inputs[index] : inputs[inputs.length - 1];

        element.focus();
        element.select();
    };

    const handleValidMultiInput = (inputElement, inputValue, curIndex, inputs) => {
        const inputLength = inputValue.length;
        const numInputs = inputs.length;

        const endIndex = Math.min(curIndex + inputLength - 1, numInputs - 1);
        const inputsToChange = Array.from(inputs).slice(curIndex, endIndex + 1);
        inputsToChange.forEach((input, index) => setInputValue(input, inputValue[index]));
        focusIndex(inputs, endIndex);
    };

    const handleInput = (inputElement, inputValue, curIndex, inputs) => {
        if (!isValidInput(inputValue)) return handleInvalidInput(inputElement);
        if (inputValue.length === 1) handleValidSingleInput(inputElement, inputValue, curIndex, inputs);
        else handleValidMultiInput(inputElement, inputValue, curIndex, inputs);
    };

    const handleValidSingleInput = (inputElement, inputValue, curIndex, inputs) => {
        setInputValue(inputElement, inputValue.slice(-1));
        focusNext(inputs, curIndex);
    };

    const handleInvalidInput = (inputElement) => {
        resetInput(inputElement);
    };

    const handleKeyDown = (event, key, inputElement, curIndex, inputs) => {
        if (key === "Delete") {
            resetInput(inputElement);
            focusPrev(inputs, curIndex);
        }
        if (key === "ArrowLeft") {
            event.preventDefault();
            focusPrev(inputs, curIndex);
        }
        if (key === "ArrowRight") {
            event.preventDefault();
            focusNext(inputs, curIndex);
        }
    };

    const handleDelete = (inputElement, curIndex, inputs) => {};

    const handleKeyUp = (event, key, inputElement, curIndex, inputs) => {
        if (key === "Backspace") focusPrev(inputs, curIndex);
    };

    const inputs = OTPContainer.querySelectorAll("input:not(#otp-value)");
    inputs.forEach((input, index) => {
        input.addEventListener("input", (e) => handleInput(input, e.target.value, index, inputs));

        input.addEventListener("keydown", (e) => handleKeyDown(e, e.key, input, index, inputs));

        input.addEventListener("keyup", (e) => handleKeyUp(e, e.key, input, index, inputs));

        input.addEventListener("focus", (e) => e.target.select());
    });
});

Advantages of OTP-Input

  1. Lightweight: OTP-Input is a lightweight solution, ensuring fast loading times and optimal performance.
  2. Versatility: Being based on Vanilla JavaScript, OTP-Input seamlessly integrates with various frameworks and libraries.
  3. Customizable: Tailor the appearance and behavior of OTP input fields to match your application's design and user experience.

Conclusion

Incorporating OTPs into your authentication process is a crucial step towards enhancing user security. By utilizing the OTP-Input library, you can achieve this in a lightweight and efficient manner. Take advantage of its simplicity and customize it to suit your application's unique requirements. Strengthen your web application's security effortlessly with OTP-Input.

Implementing secure practices not only protects your users but also builds trust in your platform. Upgrade your authentication system today with OTP-Input!

       

Advertisements

ads