React.js - Promisified Modals
Tags: react, javascript, electron
Published: 2020-04-14 15:19:56

---
title: React.js - Promisified Modals
published: true
description: Using promisified modals to create Message Boxes
tags: react, javascript, electron
---

![https://unsplash.com/@erdaest](https://images.unsplash.com/photo-1520038410233-7141be7e6f97?ixlib=rb-1.2.1&auto=format&fit=crop&w=1353&q=80 "https://unsplash.com/@erdaest")

According to [Microsoft](https://docs.microsoft.com/en-us/windows/win32/dlgbox/about-dialog-boxes#message-boxes):

> A message box is a special dialog box that an application can use to display messages and prompt for **simple** input. A message box typically contains a text message and one or more buttons.

The web might not see this type of dialog often but web technologies are used more and more to [develop desktop applications](https://github.com/styfle/awesome-desktop-js) where these message boxes are a common pattern. Modals in general may even be considered bad UX, but in some situations they might still be the best option. As stated by [NNG](https://www.nngroup.com/articles/overuse-of-overlays/), modals may be used when:

- The user is about to take an action that has **serious consequences** and is difficult to reverse.

- It’s **essential to collect** a small amount of information before letting users proceed to the next step in a process.
- The content in the overlay is **urgent**, and users are more likely to notice it in an overlay.

Let's consider a to-do list app and assume that removing items from a list is an irreversible operation, and as such, an action with serious consequences. We have a button that when triggered should remove one or more items from the list but before proceeding we want to ask user's confirmation. Putting this into code, we get something like this:

```jsx
const handleRemove = items => {
  // 1. Ask user's confirmation
  // 2. Permanently remove the items
}

return <button onClick={handleRemove}>Remove item</button>
```

How can we implement this in React without too much code?

A common pattern for showing/hiding DOM elements in React consists of this:

```jsx
const [isVisible, setVisible] = React.useState(false)

return (
  <button onClick={() => setVisible(!isVisible)}> Remove items </button>)
  {isVisible && <MessageBox>Are you sure?</MessageBox>}
)
```

However, following this approach the code would get messy really fast. Why? Because we need to define at least two handlers and to connect them somehow: one to show the MessageBox and another one to actually remove the items. The code would become hard to read because the button that says _Remove items_ is actually not removing the items but showing some other component instead. How that component leads to the actual items removal is also not obvious. On top of that, you probably want to use message boxes to confirm several other actions in the app, so the less the code you need to write, the better. We simply want to get a _yes_ or _no_ from the user, right?

The solution: **a promisified modal**, so we can do this:

```jsx
const handleRemove = async items => {
  // 1. Ask user's confirmation
  const result = await MessageBox.open({
    title: "Confirm",
    content: <p>Are you sure?</p>
    buttons: [
      {name: "Oh yeah", handler: () => "yeah"},
      {name: "Nevermind", handler: () => "nope" },
    ]
  })
  // 2. Permanently remove the items
  if(result === "yeah") {
    // ... remove the items
  }
}
```

So, how do we actually render the MessageBox? By calling `ReactDOM.render()` which allow us to specify the HTML element where is should be rendered at. Once we are done, we simply call `ReactDOM.unmountComponentAtNode()` to remove it from the DOM.

Finally, because getting user's input is an asyncronous operation, we wrap the whole thing in a Promise.

```jsx
// MessageBox.jsx

export default {
  open: props => {
    return new Promise(resolve => {
      const { container, title, content, buttons } = props
      const containerElement = document.querySelector(container)

      const handleClose = value => {
        const result = value
        ReactDOM.unmountComponentAtNode(containerElement)
        return resolve(result)
      }

      const handleButton = handler => () => {
        handleClose(handler())
      }

      ReactDOM.render(
        <Modal title={title} onClose={handleClose}>
          {content}
          {buttons.map(btn => {
            return (
              <button onClick={handleButton(btn.handler)}>{btn.name}</button>
            )
          })}
        </Modal>,
        containerElement
      )
    })
  }
}
```

And that's it. You can see a fully working example in the CodeSandbox bellow.

[![Edit React: MessageBox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-messagebox-ow9i4?fontsize=14&hidenavigation=1&theme=dark)

Let me know of what you think! 

_Originally posted at_: https://rasgo.cc/blog/tech/react-promisified-modals