Minutemailer
Fork this on GitHub

React Popup

Simple and powerful react popup component.

Install

This package is available on npm as react-popup. Install it using npm install react-popup. Currently only working in CommonJS environments.

Setup

Start by rendering the react component into an element on the page. You will need the react and react-dom packages. See configuration options at the end of this page.

Important: The component is meant to work as a global component. You should only mount it once, not everytime you want to use it, in other components. Preferably mount it as far up the DOM tree as possible to avoid positioning problems.

import React from 'react';
import ReactDom from 'react-dom';
import Popup from 'react-popup';

ReactDom.render(
    <Popup />,
    document.getElementById('popupContainer')
);

Styling

Right now we do not support css in js. We use simple classes that you need to use in order for the popup to display correctly. See demo CSS for an example.

Display a simple alert

Displaying an alert box couldn't be easier. Just call the alert method on the popup with the text as the first argument and an optional title as the second one.

Popup.alert('I am alert, nice to meet you');

Pro tip: If you dispatch multiple popups they will be queued and displayed one at the time as the popups closes.

What's your name?

The prompt helper has been removed in v0.7.0. To help you out a bit, here's an example of how you can do it yourself, the recommended way. More about plugins further down.

/** The prompt content component */
class Prompt extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            value: this.props.defaultValue
        };

        this.onChange = (e) => this._onChange(e);
    }

    componentDidUpdate(prevProps, prevState) {
        if (prevState.value !== this.state.value) {
            this.props.onChange(this.state.value);
        }
    }

    _onChange(e) {
        let value = e.target.value;

        this.setState({value: value});
    }

    render() {
        return <input type="text" placeholder={this.props.placeholder} className="mm-popup__input" value={this.state.value} onChange={this.onChange} />;
    }
}

/** Prompt plugin */
Popup.registerPlugin('prompt', function (defaultValue, placeholder, callback) {
    let promptValue = null;
    let promptChange = function (value) {
        promptValue = value;
    };

    this.create({
        title: 'What\'s your name?',
        content: <Prompt onChange={promptChange} placeholder={placeholder} value={defaultValue} />,
        buttons: {
            left: ['cancel'],
            right: [{
                text: 'Save',
                key: '⌘+s',
                className: 'success',
                action: function () {
                    callback(promptValue);
                    Popup.close();
                }
            }]
        }
    });
});

/** Call the plugin */
Popup.plugins().prompt('', 'Type your name', function (value) {
    Popup.alert('You typed: ' + value);
});

Custom buttons

You can customize the buttons with classes, text and on click actions. The value for "key" is sent directly to keymaster, check their documentation to see what you can use.

Popup.create({
    title: null,
    content: 'This popup uses the create method directly to get more control. This popup demonstrates custom buttons.',
    buttons: {
        left: [{
            text: 'Cancel',
            className: 'danger',
            action: function () {
                Popup.alert('You pressed the Cancel btn');

                /** Close this popup. Close will always close the current visible one, if one is visible */
                Popup.close();
            }
        }],
        right: [{
            text: 'Alt',
            key: 'ctrl+enter',
            action: function () {
                // Passing true as the second argument to the create method
                // displays it directly, without interupting the queue.
                Popup.create({
                    title: null,
                    content: 'I was configured to display right away, without affecting the queue. Closing this will display the previously visible popup.',
                    buttons: {
                        left: ['cancel'],
                        right: []
                    }
                }, true);
            }
        }, {
            text: 'Save',
            className: 'success',
            action: function () {
                Popup.alert('You pressed the Save btn');

                /** Close this popup. Close will always close the current visible one, if one is visible */
                Popup.close();
            }
        }]
    }
});

Reuse popups

It is possible to store popups in variables and reuse them. Instead of using one of the helper methods (alert and prompt) you use the register method. You can also set a third parameter on alert and prompt to true.

let mySpecialPopup = Popup.register({
    title: 'I am special',
    content: 'Since I am special you might need me again later. Save me!',
    buttons: {
        left: ['cancel'],
        right: ['ok']
    }
});

Popup.queue(mySpecialPopup);

Plugins

In addition to locally reusable popups you can also store your custom popups globally. Let's say you want a popover that you know you will be using on several places in your application. Instead of duplicated code, you can register it once.

Popup.registerPlugin('popover', function (content, target) {
    this.create({
        content: content,
        className: 'popover',
        noOverlay: true,
        position: function (box) {
            let bodyRect      = document.body.getBoundingClientRect();
            let btnRect       = target.getBoundingClientRect();
            let btnOffsetTop  = btnRect.top - bodyRect.top;
            let btnOffsetLeft = btnRect.left - bodyRect.left;
            let scroll        = document.documentElement.scrollTop || document.body.scrollTop;

            box.style.top  = (btnOffsetTop - box.offsetHeight - 10) - scroll + 'px';
            box.style.left = (btnOffsetLeft + (target.offsetWidth / 2) - (box.offsetWidth / 2)) + 'px';
            box.style.margin = 0;
            box.style.opacity = 1;
        }
    });
});

Popup.plugins().popover('This popup will be displayed right above this button.', element);

Note that in this example I'm using custom positioning. All popups can have a position property. It can be an object with x and y or a function. If you use a function you get complete control over the box. The box is invisible (opacity=0) by default so you need to make it visible in your function as in the example above.

Jump the queue

If you want to display the popup immediately, and go back to the previous one after the new one is closed, pass `true` as the second argument to the `create` method:

Popup.create({
    title: 'Immediate popup',
    content: 'This popup will be displayed straight away',
    className: 'alert',
    buttons: {
        right: ['ok']
    }
}, true);

Configuration

There are multiple options you can set when you attach the popup component to the DOM. See below for a complete list.

<Popup
    className="mm-popup"
    btnClass="mm-popup__btn"
    closeBtn={true}
    closeHtml={null}
    defaultOk="Ok"
    defaultCancel="Cancel"
    wildClasses={false}
    escToClose={true} />

Clear queue

Sometimes you might want to wipe the popup queue completely, making sure no more popups will be displayed after you close the current one. To do this, just call Popup.clearQueue(). Remember that this will only clear the queue, you have to close the currently visible popup yourself (Popup.close()).