Build your own OTP verification UI using React, Formik & TypeScript

Build your own OTP verification UI using React, Formik & TypeScript

OTP (One-Time Password) verification plays a crucial role in ensuring the security and integrity of online transactions, user registrations, and data privacy. Implementing OTP input functionality correctly is essential to provide a seamless and reliable user experience. In this tutorial, we will explore how to create your own OTP verification UI using React, Formik, and TypeScript. This step-by-step guide will walk you through the process of building a secure and efficient OTP verification system, highlighting the importance of OTP verification in modern web applications.

So, let’s get started and enhance the security of your applications with OTP verification!

Prerequisites

  • Basic understanding of ReactJS.
  • Basic understanding of Formik
  • Basic TypeScript type-checking understanding

Also read, How to connect Frontend and Backend in React js

Let’s Get Started

Before jumping directly into adding functionality let us build our UI first, add below HTML and CSS code into your React app,

HTML

Add the below OTP boiler code either in your app.tsx file or the component’s file, 

Note – In our input tag we pass maxlength property with value 1 so that the user can’t input more than 1 character in the input box. Also, we pass autoComplete=”one-time-code” properties, so that the input box can autofill when the user gets OTP text sent through SMS.

import "./styles.css";

const initialValues = {
  otp: [
    { digit: "" },
    { digit: "" },
    { digit: "" },
    { digit: "" },
    { digit: "" },
    { digit: "" }
  ]
};

export default function App() {
  return (
    <div className="card">
      <div className="card-header">
        <img src="./smartphone-2.svg" alt="smartphone" />
        <div className="header-text">Two-Factor Verification</div>
        <div className="header-subtext">
          Enter the verification code we sent to
        </div>
        <div className="verification-number">******789</div>
      </div>
      <form className="otp-conatiner">
        <div className="otp-subtext">Type your 6 digit security code</div>
        <div className="otp-inputs">
          {initialValues.otp.map((item, index) => {
            return (
              <input
                className="otp-input"
                type="text"
                inputMode="numeric"
                autoComplete="one-time-code"
                maxLength={1}
              />
            );
          })}
        </div>
        <button type="submit" className="submit-btn">
          Submit
        </button>
      </form>
      <div className="otp-resend">Didn’t get the code ? Resend or Call Us</div>
    </div>
  );
}

Also read, Easy tutorial to build React Autosuggest from scratch

CSS

Add Below CSS code into your index.css,

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: Inter, Helvetica, "sans-serif";
}

body {
  background-color: #f8f7fb;
}

.card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #fff;
  padding: 20px 25px;
  border-radius: 10px;
  min-width: 550px;
  min-height: 600px;
}

.card-header {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  margin-bottom: 2rem;
}

.card-header img {
  width: 30%;
  margin-bottom: 40px;
}

.header-text {
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.2;
  margin-bottom: 0.75rem;
}

.header-subtext {
  color: #a1a5b7;
  font-size: 1.15rem;
  font-weight: 500;
  margin-bottom: 1rem;
}

.verification-number {
  font-size: 1.2rem;
  font-weight: 600;
  line-height: 1.2;
  margin-bottom: 0.75rem;
}

.otp-conatiner {
  display: flex;
  flex-direction: column;
  gap: 5px;
  justify-content: left;
  align-items: center;
  margin-bottom: 1rem;
}

.otp-subtext {
  font-size: 0.775rem;
}

.otp-inputs {
  display: flex;
  flex-direction: row;
  gap: 10px;
  justify-content: center;
  padding: 20px 0;
}

.otp-input {
  font-size: 2.25rem;
  text-align: center;
  height: 60px;
  width: 60px;
}

.submit-btn {
  background-color: #009ef7;
  border: none;
  color: #fff;
  padding: calc(0.825rem + 1px) calc(1.75rem + 1px);
  cursor: pointer;
  font-weight: 600;
  border-radius: 0.625rem;
}

.otp-resend {
  color: #a1a5b7;
  font-size: 0.9rem;
  font-weight: 500;
  text-align: center;
}

Also read, Simple tutorial on React authentication with redux + Example

APP UI

Your UI would look something below,

OTP verification

Also read, How to add/remove input fields dynamically with Reactjs

Coding time

Adding Formik

First, we will try to setup and add Formik into our code, in order to handle our form. In our input field, we will pass,

formik.getFieldProps() is provided by formik to set up our input field faster, it helps us to add name and value properties to each input field.

{...formik.getFieldProps(`otp.${index}.digit`)}

Then we will add the handleOTPChange function which will basically used to update the OTP object.

onChange={(event) => handleOTPChange(event, `otp.${index}.digit`)}

When the user will enter a number, it will update the OTP object using formik.setFieldValue,

setFieldValue is used to update the given field, it compares, the given field name and updates the value.

const handleOTPChange = (
  event: React.ChangeEvent<HTMLInputElement>,
  element: string
) => {
  if (event.target.value === "") {
    return;
  }
  formik.setFieldValue(element, event.target.value);
  const nextElementSibling = event.target
    .nextElementSibling as HTMLInputElement | null;

  if (nextElementSibling) {
    nextElementSibling.focus();
  }
};

After updating the field, we then check if it has the next sibling element, by using nextElementSibling property, if yes we then shift the input focus to the next input box, which provides a smooth UI experience.

Also read, Where Non-Techies Can Get With the Programming

Then we finally add another function, inputOnKeyDown at onKeyDown event, when the user clicks on the ‘backspace’ button, it removes the value from the OTP object using formik.setFieldValue.

onKeyDown={(event) => inputOnKeyDown(event, `otp.${index}.digit`)}

After updating the field, we then check if it has a previous sibling element, by using previousElementSibling property, if yes we then shift the input focus to the prev input box, which provides a smooth UI experience.

const inputOnKeyDown = (
    e: React.KeyboardEvent<HTMLInputElement>,
    element: string
  ) => {
    const target = e.target as HTMLInputElement;
    formik.setFieldValue(element, "");

    if (e.key !== "Backspace" || target.value !== "") {
      return;
    }

    const previousElementSibling = target.previousElementSibling as HTMLInputElement | null;

    if (previousElementSibling) {
      previousElementSibling.focus();
    }
};

App Demo


Also read, Add Redux to your React app in 6 Simple Steps

Final Words

In conclusion, creating your own OTP input in React, Formik, and TypeScript can be a valuable skill, especially in web development. This article provided a comprehensive guide on how to do so, including the necessary code snippets and explanations. If you want to dive deeper into React, Formik, and TypeScript development, we encourage you to read more of our articles on these topics.