How to Create a Custom Confirm Box with React
Tags: react, tutorial, javascript, webdev
Published: 2020-11-15 06:09:57

Hi, I'm Marian and I just released my new side project called [Cow Pilot](https://www.cow-pilot.io). 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](https://dev-to-uploads.s3.amazonaws.com/i/6pwis4yywwihqqmjnlwl.gif)

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

![A confirm box in Firefox](https://dev-to-uploads.s3.amazonaws.com/i/16nnr376fwfh08qchhx0.png)

and like this in Chrome 

![A confirm box in Chrome](https://dev-to-uploads.s3.amazonaws.com/i/fc16dp3smjmqte23wagj.png)

Not pretty. It can be set up like this. 

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

## 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](https://styled-components.com/), 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.

```Javascript
/* 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*/
}
```

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. 

```Javascript
/* 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;
}
```

## 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
/* JSX */
<button 
  className="delete-button"
  onClick={() => {handleConfirmationBox()}>
    Delete
</button>
```

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

```Javascript
/* 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)
}

```

## 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.