DEV Community

Cover image for How to Create a Custom Confirm Box with React
Marian
Marian

Posted on

How to Create a Custom Confirm Box with React

Hi, I'm Marian and I just released my new side project called Cow Pilot. It's a to-do list app, but you can only add 6 tasks.

Today I wanted to share how I created a custom confirm box, since the standard ones look kinda boring and different in every browser.

Alt Text

For example, the same confirm box looks like this in Firefox

A confirm box in Firefox

and like this in Chrome

A confirm box in Chrome

Not pretty. It can be set up like this.

<button 
  className="delete button"
  onClick={() => {
    const confirmBox = window.confirm(
      "Do you really want to delete this Crumb?"
    )
    if (confirmBox === true) {
      handleDeleteCrumb(bookmark)
    }
  }}>
</button>
Enter fullscreen mode Exit fullscreen mode

Introduction

The custom variant works like this:

  • Add an opaque full screen background to the DOM
  • Below that, add a div that acts as the confirm box container
  • Inside the div add a text and the Cancel and OK buttons

In normal state, the background and the container both have the property display: none, which means they are not visible on the screen and other than visibility: hidden don't take up any space.
We make them visible by clicking on a button, for example in my case "Delete Task", which calls a function that changes display: none to display: flex (or instead of anything else that is not none)

There are several ways to make them visible:

  • use display.querySelector(".container").style.display = to unhide and hide the box
  • use useState to add and remove a class with property display: none
  • use inline styles and toggle the display: none property with useState
  • use styled components, a library I have started using recently. We pass props to the styled component and use it to toggle between display: flex and display: none

In this post I will focus on the first variant. If you are interested I can make a follow-up for the other ways as well, just let me know in the comments.

Creating the Elements

First, let's create the background. I'm adding it to be able to close the box by clicking anywhere outside of it. I also disable scrolling with overflow:hidden while the background is visible. I like to make it black and 50% opaque to accentuate the confirm box, but you can also make it completely opaque.

/* The JSX */
<>
  <div 
    className="confirm-bg" 
    onClick={() => handleConfirmationBox()}>
  </div>
</>

/* The CSS */
.confirm-bg {
  position: fixed;
  display: none;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: #202020;
  opacity: 0.55;
  overflow: hidden; /* disable scrolling*/
  z-index: 2; /* higher than all other items, but lower than 
    the confirm box*/
}
Enter fullscreen mode Exit fullscreen mode

Next we add the container. I use position: fixed to place it close to the delete button. In our component we have to add it right before the background, otherwise it will appear behind it on the screen.

/* The JSX */

<>
  <div className="container">
    <div className="confirmation-text">
      Do you really want to delete this task?
    </div>
    <div className="button-container">
      <button 
        className="cancel-button" 
        onClick={() => handleConfirmationBox()}>
          Cancel
      </button>
      <button 
        className="confirmation-button"
        onClick={handleDeleteTask}>
          Delete
        </button>
    </div>
  </div>
  <div 
    className="confirm-bg">
    onClick={() => handleConfirmationBox()}
  </div>
</>


/* The CSS */
.container {
  display: none;
  flex-direction: column;
  position: fixed;
  background-color: #f37736;
  width: 230px;
  top: 75%;
  left: 50%;
  transform: translate(-50%, -75%);
  border-radius: 0.3rem;
  padding: 1rem;
  z-index: 5; /* Higher than the z-index of the background */
}

.confirmation-text {
  display: flex;
  color: white;
  margin: 0.5rem 0 2rem;
  text-align: center;
  line-height: 2rem;
  font-size: 1.1rem;
}

.button-container {
  display: flex;
  margin-top: auto;
  justify-content: space-between;
}

.confirmation-button, delete-button {
  display: inline-flex;
  background-color: #cc0000;
  color: white;
  padding: 0.7rem 1.4rem;
  border: none;
  border-radius: 0.3rem;
  font-size: 1rem;
}

.cancel-button {
  background-color: #999999;
}

.confirmation-button:hover {
  background-color: red;
  cursor: pointer;
}

.cancel-button:hover {
  background-color: #b2b2b2;
  cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode

Toggle the elements

Now the elements are set up and we can work on showing them and hiding them again.

First we need the button that triggers the confirmation check. It can be anywhere in the component. On click, the button calls a function that changes the display property .

/* JSX */
<button 
  className="delete-button"
  onClick={() => {handleConfirmationBox()}>
    Delete
</button>
Enter fullscreen mode Exit fullscreen mode

Inside of handleConfirmationBox we will use a state to check, if we should show or hide the confirmation check. We use a boolean value and set the default to false. In the handleConfirmationBox function, we assign false to hiding the popup.

We call this function when we:

  • click on the delete task button
  • click on the cancel button
  • click anywhere outside the box, while it is visible
/* define the state */

import  { useState } from "react"

const [delTask, setDelTask] = useState(false)

/* if delTask is false, change the display properties of our 
 * two elements and change delTask to true, so that next time 
 * the function is called, the elements are hidden again
 */

const handleConfirmationBox = () => {
  if (!delTask) {
    document.querySelector(".confirm-bg").style.display = "flex"
    document.querySelector(".container").style.display = "flex"
    setDelTask(true)
  } else {
    document.querySelector(".confirm-bg").style.display = "none"
    document.querySelector(".container").style.display = "none"
    setDelTask(false)
}

Enter fullscreen mode Exit fullscreen mode

Final words

And that's it. Now the confirmation will look the same on all devices and we can customize it the way we want. Like I say, there are several ways to achieve the hide/unhide. I personally like styled components because I can just pass the delTask state as prop and change the display property based on that.

If you have any questions or if I missed something, please let me know.

Top comments (1)

Collapse
 
ridoansaleh profile image
Ridoan

Nice