Login form component in react

Learn how to create login form in react.

Login or signup form is used to allow users to register and save their data and later access it whenever they need it on any given particular websites.

As react follows one-way binding and form elements have their own states so newbies often finding it little difficult to handle forms.

In this tutorial we will learn how to create a simple login form, validate it, and handle it.

For our development we will be using few extra packages which will really ease our life.

  • classnames: It helps us to use CSS classes as javascript objects, we just need to name our CSS file as filename.module.css.
  • lodash: Set of helpful utility functions.

Following is the folder structure of our component.
React login folder structure

Login form component in react

Let us begin with the development by importing all the required packages and setting up the structure.

import React, { Component } from "react";
import styles from "./index.module.css";
import { isEmpty } from "lodash";
import Button from "../Button";
import Input from "../Input";

class LoginForm extends Component {
   //Other code will go here
}

export default LoginForm;

As we have already created the Button and the Input component we will be reusing them in our development.

Create the state to store and monitor the changes.

 state = {
    username: "",
    password: "",
    isLoading: false,
    error: {
      status: false,
      message: ""
    },
    success: false
  };

We are storing the user credentials as well different state of the component. For error we storing the error message as well, you can do the same for the success.

Now lets create the layout of the component so that we can then decide what different things we need to track.

render() {
    const { username, password, isLoading, error, success } = this.state;

    return (
      <>
        <div className={styles.wrapper}>
          {/* Form element */}
          <form className={styles.box} onSubmit={this.handleSubmitClick}>
            <div className={styles.container}>
              <div className={styles.header}>Sign in</div>

              {/* User credentials input */}
              <div className={styles.content}>
                <Input
                  label="Username"
                  name="username"
                  placeholder="your username"
                  className={styles.userType}
                  value={username}
                  onKeyDown={this.handleKeyPressed}
                  onChange={this.handleInputChange}
                />
                <Input
                  type="password"
                  label="Password"
                  name="password"
                  placeholder="your password"
                  className={styles.userType}
                  value={password}
                  onKeyDown={this.handleKeyPressed}
                  onChange={this.handleInputChange}
                />
              </div>

              {/* Submit Button */}
              <div className={styles.footer}>
                <Button
                  className={styles.submitBtn}
                  type="submit"
                  label="Sign in"
                  disabled={this.shouldSubmitDisable()}
                  onClick={this.handleSubmitClick}
                  isLoading={isLoading}
                />
              </div>

              {/* Forgot password */}
              <div className={styles.forgotPassword}>
                <span>
                  forgot password?
                </span>
              </div>

              {/* show error message */}
              {error.status && (
                <div className={styles.error}>{error.message}</div>
              )}

              {/* Show success Message */}
              {success && (
                <div className={styles.success}>Login Successful!.</div>
              )}
            </div>
          </form>
        </div>
      </>
    );
  }

As you can see we have wrapped everything inside a form element because we want user to login even when enter button is pressed.

Everything else is pretty much straight forward, sign in button will be enabled only when all the input is filled and even if the inputs are focused and enter button is pressed then form will be submitted.

At the bottom show the respective messages depending on the state of the component.

Create the input change handler to store the values of the input entered.

handleInputChange = ({ name, value }) => {
    this.setState({
      [name]: value,
      error: {
        status: false,
        message: ""
      }
    });
  };

[name]:value helps us to dynamically set the key and assign value to it.

Every time inputs are changed, we want to make sure that error state is reset. There is no need to reset the success because after successful login we generally redirect to different page.

Now lets create the validation function to make sure our form is not submitted with empty values.

  shouldSubmitDisable = () => {
    return isEmpty(this.state.username) || isEmpty(this.state.password);
  };

The major thing pending right now is creating the submit function which will perform login. So lets do it.

handleSubmitClick = async () => {
    const { username, password } = this.state;
    this.setState({ isLoading: true });

    try {
      //Replace this with api call
      //Or action
      if (username === "Prashant Yadav" && password === "123456789") {
        this.setState({
          success: true
        });
      } else {
        this.setState({
          error: {
            status: true,
            message: "Invalid Credentials"
          }
        });
      }
    } catch (e) {
      this.setState({
        error: {
          status: true,
          message: e
        }
      });
    } finally {
      this.setState({
        isLoading: false
      });
    }
  };

Currently I am just doing a dummy check with the mock data, but you will need to make the api call and validate the credentials on the server.

That is why I have created an async function and place everything inside a try/catch block.

The last thing pending is listening to the enter button press and then calling this submit function.

  handleKeyPressed = e => {
    if (e.event.key === "Enter" && !this.shouldSubmitDisable()) {
      this.handleSubmitClick();
    }
  };

We check if the enter button is pressed and it is valid to submit the form then only call the function for login.

In forgot password case, right now I have kept nothing but you can assign a function on its click event and write the code as per you requirement.


Complete login form component code in react

import React, { Component } from "react";
import styles from "./index.module.css";
import { isEmpty } from "lodash";
import Button from "../Button";
import Input from "../Input";

class LoginForm extends Component {
  state = {
    username: "",
    password: "",
    isLoading: false,
    error: {
      status: false,
      message: ""
    },
    success: false
  };

  handleInputChange = ({ name, value }) => {
    this.setState({
      [name]: value,
      error: {
        status: false,
        message: ""
      }
    });
  };

  shouldSubmitDisable = () => {
    return isEmpty(this.state.username) || isEmpty(this.state.password);
  };

  handleKeyPressed = e => {
    if (e.event.key === "Enter" && !this.shouldSubmitDisable()) {
      this.handleSubmitClick();
    }
  };

  handleSubmitClick = async () => {
    const { username, password } = this.state;
    this.setState({ isLoading: true });

    try {
      //Replace this with api call
      //Or action
      if (username === "Prashant Yadav" && password === "123456789") {
        this.setState({
          success: true
        });
      } else {
        this.setState({
          error: {
            status: true,
            message: "Invalid Credentials"
          }
        });
      }
    } catch (e) {
      this.setState({
        error: {
          status: true,
          message: e
        }
      });
    } finally {
      this.setState({
        isLoading: false
      });
    }
  };

  render() {
    const { username, password, isLoading, error, success } = this.state;

    return (
      <>
        <div className={styles.wrapper}>
          {/* Form element */}
          <form className={styles.box} onSubmit={this.handleSubmitClick}>
            <div className={styles.container}>
              <div className={styles.header}>Sign in</div>

              {/* User credentials input */}
              <div className={styles.content}>
                <Input
                  label="Username"
                  name="username"
                  placeholder="your username"
                  className={styles.userType}
                  value={username}
                  onKeyDown={this.handleKeyPressed}
                  onChange={this.handleInputChange}
                />
                <Input
                  type="password"
                  label="Password"
                  name="password"
                  placeholder="your password"
                  className={styles.userType}
                  value={password}
                  onKeyDown={this.handleKeyPressed}
                  onChange={this.handleInputChange}
                />
              </div>

              {/* Submit Button */}
              <div className={styles.footer}>
                <Button
                  className={styles.submitBtn}
                  type="submit"
                  label="Sign in"
                  disabled={this.shouldSubmitDisable()}
                  onClick={this.handleSubmitClick}
                  isLoading={isLoading}
                />
              </div>

              {/* Forgot password */}
              <div className={styles.forgotPassword}>
                <span>forgot password?</span>
              </div>

              {/* show error message */}
              {error.status && (
                <div className={styles.error}>{error.message}</div>
              )}

              {/* Show success Message */}
              {success && (
                <div className={styles.success}>Login Successful!.</div>
              )}
            </div>
          </form>
        </div>
      </>
    );
  }
}

export default LoginForm;

Complete style code of login form component.

As our Button and Input component are already styled, we have just added little style to the remaining parts.

.container {
  padding: 0 32px;
  width: 100%;
}

.wrapper {
  display: flex;
  justify-content: center;
  height: 100vh;
  background-color: #f7f8fa;
  background: linear-gradient(90deg, #ffffff 0%, #ffffff 20%, #f7f8fa 98.27%);
}

.box {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  height: 365px;
  max-width: 460px;
  background-color: #fff;
  box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 3px;
  padding: 20px;
  top: 50%;
  transform: translateY(-50%);
}

.logoWrapper {
  display: flex;
  justify-content: center;
  width: 100%;
}

.content {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.content > input {
  margin-bottom: 15px;
  box-shadow: rgba(0, 0, 0, 1) 0px 0px 0px 1px inset,
    rgba(28, 28, 29, 1) 0px 0px 2px inset;
}

.header {
  display: inline-block;
  position: relative;
  width: 100%;
  font-weight: 600;
  font-size: 20px;
  text-align: center;
  line-height: 25px;
  color: #1d1c22;
  padding: 10px 0;
}

.footer {
  display: flex;
  width: 100%;
  text-align: right;
  bottom: 0;
  left: 0;
  padding: 0 0 15px;
  justify-content: flex-end;
}

.submitBtn {
  height: 40px;
}

.error,
.success {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  width: 100%;
  position: relative;
  height: 24px;
  font-size: 16px;
  padding: 24px 0;
  font-weight: 600;
  letter-spacing: 0.5px;
}

.error {
  color: #ec454d;
}

.success {
  color: #8bc34a;
}

.forgotPassword {
  text-align: right;
  width: 100%;
  color: #004bdc;
  text-transform: capitalize;
  font-weight: 600;
}

.forgotPassword > a {
  cursor: pointer;
  color: #8bc34a;
}

.forgotPassword > a:hover {
  color: blue;
}

Input

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import LoginForm from "./Components/LoginForm";
import * as serviceWorker from "./serviceWorker";

ReactDOM.render(
  <div className="abc">
    <LoginForm />
  </div>,
  document.getElementById("root")
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Output

React login form