Create alert box in react

Learn how to create alert box in react.

Alerts are used to show notifications. They are of different variants which gives user response for their different actions.

We will also create similar type of alert box in react which will have different option and can auto close after specified amount of time.

There are few extra packages we will be using for our development.

  • prop-types: To validate the props.
  • classnames: This packages helps us to use CSS classes as javascript objects, we just need to name our CSS file as filename.module.css to make it work.

Following is the folder structure of our component.
React alert box folder structure

Let us begin with our development by importing all the required packages at the top.

import React, { Component } from "react";
import PropTypes from "prop-types";
import cx from "classnames";
import styles from "./index.module.css";

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

export default AlertBox;

We are creating stateful component using class because we need to use different lifecycle methods for handling the auto close feature.

Validate the props at the beginning to make sure we build our component as we want.

 static propTypes = {
    show: PropTypes.bool.isRequired,
    autoClose: PropTypes.bool.isRequired,
    time: PropTypes.number.isRequired,
    message: PropTypes.string.isRequired,
    onClose: PropTypes.func,
    variant: PropTypes.oneOf(["danger", "primary", "basic"]).isRequired,
    placement: PropTypes.oneOf(["top", "bottom"]).isRequired
  };

  static defaultProps = {
    message: "",
    show: false,
    autoClose: false,
    time: 3000,
    variant: "primary",
    placement: "top"
  };

These are some of the props we need to make a basic alert box.

We have also defined the default props in case the requested props are not provided. In message we are only accepting string,but you can change it to accept element as well.

Now lets define the layout of our component. Creating the layout first helps me in deciding what all methods I need in the component.

 render() {
    const { message, variant, placement } = this.props;
    const { show } = this.state;
    return (
      show && (
        <div
          className={cx(styles.alertBox, styles[variant], styles[placement])}
        >
          <div>{message}</div>
          <span onClick={this.onClose} className={styles.close}>
            x
          </span>
        </div>
      )
    );
  }

Let us start by creating the state first to store the changes of the component.

  state = {
    show: this.props.show
  };

You can define it directly like this or inside constructor. Its up to you how you want.

Now as we have feature called auto close that is why we need to start a timer to close the alert after specified amount of time. The best place to do it is in the componentDidMount life cycle method.

 
  startTimer = () => {
    const { autoClose, time, show, onClose } = this.props;
    if (autoClose && show) {
      this.timer = setTimeout(() => {
        this.setState({
          show: false
        });

        onClose && onClose(false);
      }, time);
    }
  };

  componentDidMount() {
    this.startTimer();
  }

This will start the timer after the component is mounted. We have also created a function to start the timer because we will be reusing it.

When the component will unmout it is necessary to remove the timer to clear the memory. Do that inside componentWillUnmount.

  componentWillUnmount() {
    clearTimeout(this.timer);
  }

As these can be controlled component and after closing we are returning the value to the parent.

There is possibility that we can receive the update props to show the alert again. So if the auto close is true and it is asked to show the alert again we need to handle it properly.

The best place to do this is inside the componentDidUpdate method. Because in this we can compare the previous and the current prop and state.

  componentDidUpdate(prevProps) {
    const { show } = this.props;
    if (show !== prevProps.show) {
      this.setState({
        show
      });

      if (show) {
        this.startTimer();
      } else {
        clearTimeout(this.timer);
      }
    }
  }

The last thing pending is that alert box can also be manually closed so listen to the click handler of the close button.

  onClose = () => {
    const { onClose } = this.props;
    this.setState({
      show: false
    });
    onClose && onClose(false);
    clearTimeout(this.timer);
  };

If user closes the alert before timer closes it is necessary to clear the timer.

Complete code of alert box component in react.

import React, { Component } from "react";
import PropTypes from "prop-types";
import cx from "classnames";
import styles from "./index.module.css";

class AlertBox extends Component {
  static propTypes = {
    show: PropTypes.bool.isRequired,
    autoClose: PropTypes.bool.isRequired,
    time: PropTypes.number.isRequired,
    message: PropTypes.string.isRequired,
    onClose: PropTypes.func,
    variant: PropTypes.oneOf(["danger", "primary", "basic"]).isRequired,
    placement: PropTypes.oneOf(["top", "bottom"]).isRequired
  };

  static defaultProps = {
    message: "",
    show: false,
    autoClose: false,
    time: 3000,
    variant: "primary",
    placement: "top"
  };

  state = {
    show: this.props.show
  };

  startTimer = () => {
    const { autoClose, time, show, onClose } = this.props;
    if (autoClose && show) {
      this.timer = setTimeout(() => {
        this.setState({
          show: false
        });

        onClose && onClose(false);
      }, time);
    }
  };

  componentDidMount() {
    this.startTimer();
  }

  componentWillUnmount() {
    clearTimeout(this.timer);
  }

  componentDidUpdate(prevProps) {
    const { show } = this.props;
    if (show !== prevProps.show) {
      this.setState({
        show
      });

      if (show) {
        this.startTimer();
      } else {
        clearTimeout(this.timer);
      }
    }
  }

  onClose = () => {
    const { onClose } = this.props;
    this.setState({
      show: false
    });
    onClose && onClose(false);
    clearTimeout(this.timer);
  };

  render() {
    const { message, variant, placement } = this.props;
    const { show } = this.state;
    return (
      show && (
        <div
          className={cx(styles.alertBox, styles[variant], styles[placement])}
        >
          <div>{message}</div>
          <span onClick={this.onClose} className={styles.close}>
            x
          </span>
        </div>
      )
    );
  }
}

export default AlertBox;

Complete style code of alert box in react.

The style is very simple, we just need to provide different variants.

//index.module.css
.alertBox {
  position: fixed;
  width: 80%;
  left: 10%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border-radius: 5px;
  background: #eee;
  border: 1px solid #aba3a3;
}

.bottom {
  bottom: 5%;
}

.top {
  top: 5%;
}

.danger {
  background: #ff5722;
  border: 1px solid #bf360c;
}

.primary {
  background: #8bc34a;
  border: 1px solid #33691e;
}

.basic {
  background: #00bcd4;
  border: 1px solid #006064;
}

.close {
  font-size: 20px;
  cursor: pointer;
  font-weight: 600;
}

Input

import React, { Component } from "react";
import AlertBox from "./index";

class AlertBoxTest extends Component {
  state = {
    isActive: true
  };

  onChange = isActive => {
    this.setState({
      isActive
    });
  };

  onClick = () => {
    this.setState({
      isActive: !this.state.isActive
    });
  };

  render() {
    const { isActive } = this.state;
    return (
      <>
        <AlertBox
          show={isActive}
          onClose={this.onChange}
          message={"Primary!: AlertBox"}
          autoClose={false}
        />

        <AlertBox
          show={isActive}
          onClose={this.onChange}
          message={"Danger!: AlertBox"}
          autoClose={false}
          variant={"danger"}
        />

        <AlertBox
          show={isActive}
          onClose={this.onChange}
          message={"Basic!: AlertBox"}
          autoClose={false}
          variant={"basic"}
        />
      </>
    );
  }
}

export default AlertBoxTest;

Output

React alert box