Introduction

In real applications, we often see confirmation dialogs in various situation e.g. posting on SNS, promoting paid plans, purchase confirmation etc. Sometimes they are annoying but still important to be informative to users.

With HTML5.2 <dialog/> or jQuery, there is a method to open such dialogs, but the situation is a bit different in React. Let’s check how they differ.

*Update* 2018/7/19 Added Babel example.

How to open a dialog in React?

Although <dialog/> element of HTML 5.2 is already released, dialog of jQuery UI is still a popular library at this moment. With jQuery UI, a dialog can be opened like this,

<div id="dialog" title="Basic dialog">

<p>Hello World!</p>

</div> // in script tag

$(function() {

$("#dialog").dialog();

});

An example of jQuery UI Dialog

In contrary, opening a dialog using react-modal in React/JSX looks like this.

<ReactModal isOpen={this.state.isOpen}>

<p>Hello World!</p>

<button>OK</button>

</ReactModal>

An example of react-dialog

It can be opened by changing the state with isOpen = true , but there is no method like .dialog() in jQueryUI. What we have to do is to manage isOpen state.

Managing dialog state

The isOpen state can be managed in any way: Class state, HoC, Redux, etc. However, such state should not be managed by Redux because it is local and isolated from global state in most case. There is a component, StateProvider from reenhance-components which provides state and updater. It can be used like this.

const ModalState = StateProvider(false); const HelloModal = () => (

<ModalState>

{({ state: isOpen, setState: setIsOpen }) => (

...

)}

</ModalState>

);

To open a dialog by clicking a button, Both the button and modal must be enclosed with the state. Here is the example.

const ModalState = StateProvider(false); const HelloModal = () => (

<ModalState>

{({ state: isOpen, setState: setIsOpen }) => (

<div>

<button onClick={() => setIsOpen(true)}>Push me</button>

<ReactModal

isOpen={isOpen}

shouldCloseOnEsc={true}

onRequestClose={() => setIsOpen(false)}

className='modal'

>

<p>Hello modal dialog!</p>

<button onClick={() => setIsOpen(false)}>OK</button>

</ReactModal>

</div>

)}

</ModalState>

);

Tha’ts all. Let’s try it on the CodePen below.

You may feel it strange putting a modal at the same level of button. It makes sense because such implementation makes a bit difficult to reuse the component.

Let dialogs open in declarative way in JSX

Because JSX is a kind of declarative DSL, we can declare a button with confirmation dialog like this.

<WithConfirm>

<button onClick={...)}>Increment</button>

</WithConfirm>

The enclosing component, WithConfirm can be implemented by these steps.

Get the handler of onClick from child’s props.

from child’s props. Attach the handler to ‘OK’ button of modal dialog.

Replace onClick prop of children’s props with a handler which opens modal dialog.

A parent component can access the props of children via children.props . To remove onClick from children, React.cloneElement can clone them with new props. So, the render method will be something like this.

const newChildren = React.Children.map(children,

(child) => React.cloneElement(child, {

onClick: () => setIsOpen(true),

})); return (

<>

{newChildren}

<ConfirmModal

isOpen={isOpen}

setIsOpen={setIsOpen}

onOkClick={children.props.onClick}

/>

</>

);

Here is a working example on CodePen. Try clicking buttons and check what happens.

Conclusion

It may seem difficult to show dialogs in React at first sight, but the markup can be pretty much clarified thanks to JSX and declarative-ness of React.