Modals or modal boxes are very common application elements used in web design nowadays. Modals allow to show and draw the user’s attention to crucial information by overlaying a small element over the same website page they user is on. Modals improve the usability of sites and decrease unnecessary page reloads.

Modals can have many practical uses. Frequently they are used for displaying login and signup forms, contact and comment forms, and images and videos. However, there are many other use case examples for modals.

Mostly all modern front-end development frameworks include modals in their libraries. You find modals within Semantics UI, Bootstrap, Material-UI, Ant-design, React-Bootstrap, Office UI Fabric, React-md, Gestalt, and Semantic-UI-React.

All these frameworks are very powerful and provide dozens of efficient, stiled, reusable components. Many of them also allow customization.

However, you might also be considering building your custom modals in your application instead of recurring to frameworks. This post will guide you on how to implement a basic modal on your React app. You can find the final code for this case example in the following Github repository. You can also check the code example in CodePen.

If you want to code along the steps in this post, create a new React app. You can use npm init react-app app-name or follow the documentation.

First, remove most of the code from App.js. Our next step will be to create a Modal component. The modal will be rendered from our App component. Import it inside App.js and call it inside the className=”App” container.

//App.jsimport React, { Component } from 'react';import './App.css';import Modal from './Modal'class App extends Component {   render() {     return (       <div className="App">
<Modal />
</div>
); }}export default App;

Then, on the App.css file, add the following code to keep the content centered. You can also add a background image that will help visualize the overlaying modal.

//App.cssbody {
background-image: url("https://upload.wikimedia.org/wikipedia/commons/8/8a/Tree_icon_w_outline.png");
background-repeat: no-repeat;
background-position: right left;
background-attachment: fixed;
}
.App {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: black;
}

The Modal Component

We are already importing Modal.js but it doesn’t exist yet. Let’s create a functional component named Modal.js. Compared to class components, functional components are much simpler and lightweight. In this basic example, a functional component is preferred because the component doesn’t have to store state -it will be passed as props-, access lifecycle methods, and it just has to display content. Functional components return JSX instead of using a render method and don’t extend Component so they don’t inherit the functionality to store state. However, functional components can still receive props by passing props as argument for the function.

The modal will contain two containers. The parent one has className=“modal” and the sibling has className=“modal-content”. The modal-content container will wrap the information to be displayed including a Close button. The Close button is built with a span tag so it stays inline with any other elements in the container. div elements create a line-break before and after them.

//Modal.jsimport React from 'react';const Modal = props => {  return (     <div className="modal">
<div className="modal-content">
<span className="close">&times;</span>
</div>
</div>
);}export default Modal;

Adding CSS to the Modal

In your App.css file, add the following code. Each property is commented so you can follow along.

//App.css/* MODAL */
/* Background effect. It covers the entire site */
.modal {
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Overlay effect: translucent background: black w/ partial opacity */
z-index: 1; /* Overlay effect: positioned over other containers */
width: 100%; /* Full width */
height: 100%; /* Full height */
position: fixed; /* Fix position on the top-left corner*/
top: 0;
left: 0;
overflow: auto; /* Enable scroll if needed */
padding-top: 80px; /* Location of the content container */
}
/* Modal content */.modal-content {
background-color: white;
width: 70%; /* Width in proportion to its parent container*/
max-width: 640px; /* Max width where it stops expanding */
height: 70%; /* Height in proportion to its parent container */
margin: auto; /* Auto margin according to the element width */
padding: 10px;
border: 1px solid black;
border-radius: 20px; /* Optional. Rounds container corners */
}
/* Close button */.close {
color: #aaaaaa;
float: right; /* Positioned to the right of the parent container whichever size it is */
font-size: 25px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}

Passing state and props

The modal container is still lacking the property that makes it a modal: toggling its visibility, alternating between hidden and visible. We can use to approaches: the display property or a ternary operator. First, we will use the display property. Then, we’ll simplify it just displaying the Modal component with a ternary operator.

Display property. Inside your Modal component create a const divStyle which will style the className=”modal” inline (style = { divStyle }). The display property will alternate between 'block' (visible) and 'none' (hidden). The modal will receive props from its parent container App.js. When props.displayModal is true, the modal with be visible. You can use an ternary operator as in the example.

The modal visibility will be stored in the App container state (modal). Certain elements in the app will be responsible for toggling modal: clicking the Close button and clicking on the outer container (className=”modal”). The selectModal() function -responsible of toggling the modal state with this.setState method- will be passed as props to the Modal container as props.closeModal. In order to prevent the modal from closing when clicking on the className=”modal-content” container, we have to stop the click event from bubbling up from the children container to the parent container. We can use e => e.stopPropagation() .

//Modal.jsimport React from 'react';const Modal = props => {

const divStyle = {
display: props.displayModal ? 'block' : 'none'
};
function closeModal(e) {
e.stopPropagation()
props.closeModal()
}
return (
<div
className="modal"
onClick={ closeModal }
style={divStyle}
>
<div
className="modal-content"
onClick={ e => e.stopPropagation() } >
<span
className="close"
onClick={ closeModal }>&times;
</span>
</div> </div>
);
}
export default Modal;

Now we need to modify App.js , create the state, and the selectModal function and pass the props to the modal. Add a p tag before the modal container that will open the modal when clicked.

//App.jsimport React, { Component } from 'react';
import './App.css';
import Modal from './Modal'
class App extends Component {
state = {
modal: false
}

selectModal = (info) => {
this.setState({modal: !this.state.modal})
// true/false toggle
}

render() {
return (
<div className="App">
<p onClick={ this.selectModal }
>Open Modal</p>
<Modal
displayModal={this.state.modal}
closeModal={this.selectModal}
/>
</div>
);
}}
export default App;

Ternary operator. Instead of toggling the css-property display, we could refactor and simplify the code with a simple ternary operator inside Modal.js, replace the return elements in modal container with the following code. Create a variable modal that stores the previous returned elements.

Now, the modal will render only when this.state.displayModal (or props.displayModal)) is true. You can check this code version in CodePen.

return ( props.displayModal ? modal : null);

You already have you Modal component up and running. You could refactor you App and Modal component so the modal displays different content. Check the final code in the repository if you want to see how.

Final modal

Enjoy your Modal!

--

--