loading...

Building a modal in React.

achowba profile image Atauba Prince ・4 min read

In this tutorial, we are going to build a modal in React. Below is a demo of it.

Prerequisites

These are the prerequisites required to follow this tutorial.

  • Knowledge of React (You should have at least a basic understanding of state and props).

  • An installation of Node JS on your PC.

  • create-react-app installed on your PC.

Initial Setup

Initialize the project by running the command below in the root directory of your project, it installs the libraries and tools needed to start the project.

create-react-app basic-modal

Building the Components

Before creating the components or writing any code, follow the steps below to delete unwanted files and also create the files needed for the project.

  1. Delete the following files: app.css, app.test.js, logo.svg and registerServiceWorker.js from the src folder.

  2. Create a folder in the src directory and name it components.

  3. In the components folder, create another folder called Modal.

  4. In the Modal folder, create two files namely Modal.js and Modal.css.

After doing this, your project structure should be similar to this:

Modal.js

Open the Modal.js file in the components folder and add the following code.

import React from 'react';

import './Modal.css';

const modal = (props) => {
    return (
        <div>
            <div className="modal-wrapper"
                style={{
                    transform: props.show ? 'translateY(0vh)' : 'translateY(-100vh)',
                    opacity: props.show ? '1' : '0'
                }}>
                <div className="modal-header">
                    <h3>Modal Header</h3>
                    <span className="close-modal-btn" onClick={props.close}>Γ—</span>
                </div>
                <div className="modal-body">
                    <p>
                        {props.children}
                    </p>
                </div>
                <div className="modal-footer">
                    <button className="btn-cancel" onClick={props.close}>CLOSE</button>
                    <button className="btn-continue">CONTINUE</button>
                </div>
            </div>
        </div>
    )
}

export default modal;


The modal component has three props which are:

  • show - a boolean value indicating whether the modal should be shown or not.

  • close - a function which closes the modal when the cancel button is clicked

  • children - which is passed between the opening and closing tags of the modal component as the contents of the modal.

The modal component is a functional component that receives the contents of the modal as the children of the component. The modal footer also contains a button that executes a function to close the modal when it is clicked. The function is passed as a prop to the modal component. The inline style in the modal-wrapper div contains a conditional statement that sets the value of visibility status of the modal depending on the boolean value of the show props.

Modal.css

Add the following code to the Modal.css file in order to add styling to the modal component.

.modal-wrapper {
    background: white;
    border: 1px solid #d0cccc;
    box-shadow: 0 5px 8px 0 rgba(0,0,0,0.2), 0 7px 20px 0 rgba(0,0,0,0.17);
    margin: 100px auto 0;
    transition: all .8s;
    width: 60%;
}

.modal-header {
    background: #263238;
    height: 40px;
    line-height: 40px;
    padding: 5px 20px;
    text-align: right;
}

.modal-header h3 {
    color: white;
    float: left;
    margin: 0;
    padding: 0;
}

.modal-body {
    padding: 10px 15px;
    text-align: center;
}

.modal-footer {
    background: #263238;
    height: 35px;
    padding: 15px;
}

.close-modal-btn {
    color: white;
    cursor: pointer;
    float: right;
    font-size: 30px;
    margin: 0;
}

.close-modal-btn:hover {
    color: black;
}

.btn-cancel, .btn-continue {
    background: coral;
    border: none;
    color: white;
    cursor: pointer;
    font-weight: bold;
    outline: none;
    padding: 10px;
}

.btn-cancel {
    background-color: #b71c1c;
    float: left;
}

.btn-continue {
    background-color: #1b5e20;
    float: right;
}

.back-drop {
    background-color: rgba(48, 49, 48, 0.42);
    height: 100%;
    position: fixed;
    transition: all 1.3s;
    width: 100%;
}

.open-modal-btn {
    margin: 15px;
    padding: 10px;
    font-weight: bold;
}


App.js
import React, { Component } from 'react';

import Modal from './components/Modal/Modal';

class App extends Component {

    constructor() {
        super();

        this.state = {
            isShowing: false
        }
    }

    openModalHandler = () => {
        this.setState({
            isShowing: true
        });
    }

    closeModalHandler = () => {
        this.setState({
            isShowing: false
        });
    }

    render () {
        return (
            <div>
                { this.state.isShowing ? <div onClick={this.closeModalHandler} className="back-drop"></div> : null }

                <button className="open-modal-btn" onClick={this.openModalHandler}>Open Modal</button>

                <Modal
                    className="modal"
                    show={this.state.isShowing}
                    close={this.closeModalHandler}>
                        Maybe aircrafts fly very high because they don't want to be seen in plane sight?
                </Modal>
            </div>
        );
    }
}

export default App;


The App.js file contains two custom functions which are:

  • openModalHandler() - a function that sets the state of isShowing to true thereby opening the modal.

  • closeModalHandler() - a function that sets the state of isShowing to false thereby closing the modal.

In the render method, a backdrop div is dynamically added based on the visibility of the modal and also an onClick listener is passed to the div so it can control the opening and closing of the modal. A button is also added with onClick listener to control the opening of the modal.

The modal component which was previously is imported and used in the render method with the values of the props passed to it.

Testing the modal

Run npm start in the root directory of your project to view the modal.

Project Repo

Thanks.

Posted on by:

Discussion

pic
Editor guide
 

Hi, nice article.

We prefer to use Modal components wrapped in a component which use ReactDOM.portal (comes with 16v) for better UI mechanism. Modals and popups are looks familiar but functionality. For example; you have a form in popup, and you have to show a modal if it’s successfully posted or failed badly. Modals needs to be above popup. We’ve created 2 roots like app-root; popup-root and modal-root in a large-scaled application. By this way render methods stay clean and UI flows properly without trading CSS hacks, thanks to DOM order.

Thank you for this article (:

 

Thanks for the comment, this is the first time I am hearing about ReactDOM.portal, I will go and check it out πŸ™‚.

 

(Y) basically it allows you to use components outside of your app-root.

See you (:

 

Nice write-up! But perhaps not the best to put the children in a <p>? Good article. :)

 

Noted...thanks πŸ™‚

 

Hi,
why use two functions (openModalHandler and closeModalHandler) when you can simply have:

toggleModal = () => {
this.setState(prevState=> {
isShowing: !prevState.isShowing
})
}

and also in this kind of situations wouldn't it be more optimal to use functional component with react hooks instead of class?

 

Thanks for the suggestion on using the conditional operator. Also, at the time this post was published, React Hooks didn't exist.

 

My Page is very big and there is various open modal button in the center ,bottom and top . but the modal is open in top only... i want it scrollable as per where my button is.... like if i scroll down then this modal also go with it,... how can i do it??? @Atauba Prince

 

Hi, if i want to add Function on Continue button how can i do that?
basically i want to display a dropdown menu as i click continue button

 

Hello
Add this below the closeModalHandler

continueFunction = () => {
    // your function body goes here
}

and then change the continue button to this

<button className="btn-continue" onClick={props.close}>CONTINUE</button>