How To Build A reusable Modal in React
April 10, 2020

Source code to this tutorial is found here Github

Building a modal in react is challenging, most especially for beginners.

The question to ask is why would we want to implement a modal component from scratch instead of relying on the existing react modal component library?

  1. It helps to understand how the modal component works under the hood.
  2. External components tend to increase the overall project size, Building your reusable component ensures you have only what you need in your project i.e. not handling other scenarios that might come with an existing pre-built component which you might not need.

Implementing the Modal component

we create a modal.js file and add the following first

1import React from 'react';
2import './modal.css';
3
4const Modal = (props) => {
5 const { closeModal } = props;
6 return (
7 <div className="overlay">
8 <div className="content">
9 { closeicon() }
10 {props.children}
11 </div>
12 </div>
13 );
14};
15
16export default Modal;

the above is almost all we need to implement the modal component, what I did was to make the content of our modal (div styled as a content) a child of its parent container (div styled as an overlay).

Also, note the children of the modal component would be rendered inside the content div.

Implementing the close icon function: For the sake of this tutorial I used react font awesome icon.

npm i react-fontawesome

1const closeicon = () => (
2 <FontAwesome
3 name="times"
4 onClick={closeModal}
5 style={{
6 color: '#000000',
7 padding: '10px',
8 cursor: 'pointer',
9 backgroundColor: 'transparent',
10 border: 0,
11 position: 'absolute',
12 top: '0.3rem',
13 right: '0.5rem',
14 }}
15 />
16 );

what I did from above is to create a function that returns a font-awesome icon. I added its onClick property. the value of the onClick property must be passed as props into the modal component.

The for the font awesome icon to be displayed add the following cdn to your public/index.html file

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

Note: you can always choose to use an icon within your project and apply the above styling I used for my font-awesome icon and onClick property.

The whole component so far

1import React from 'react';
2import './modal.css';
3import FontAwesome from 'react-fontawesome';
4
5const Modal = (props) => {
6 const { closeModal } = props;
7
8 const closeicon = () => (
9 <FontAwesome
10 name="times"
11 onClick={closeModal}
12 style={{
13 color: '#000000',
14 padding: '10px',
15 cursor: 'pointer',
16 backgroundColor: 'transparent',
17 border: 0,
18 position: 'absolute',
19 top: '0.3rem',
20 right: '0.5rem',
21 }}
22 />
23 );
24
25 return (
26 <div className="overlay">
27 <div className="content">
28 { closeicon() }
29 {props.children}
30 </div>
31 </div>
32 );
33};
34
35
36export default Modal;

From the above, we can see that closeModal function was passed as props to the modal component.

1.overlay {
2 position: fixed;
3 display: block;
4 overflow: auto;
5 width: 100%;
6 height: 100%;
7 top: 0;
8 left: 0;
9 right: 0;
10 bottom: 0;
11 background-color: rgba(0,0,0,0.5);
12 z-index: 999;
13 cursor: pointer;
14 }
15
16.content {
17 margin: 15% auto;
18 background-color: white;
19 border-radius: 0.25rem;
20 width: 50vw;
21 padding: 2rem;
22 position: relative;
23 }

from the CSS style above, things to note is includes:

  • The overlay position property is fixed i.e. it’s positioned relative to the viewport.
  • The content has 50vw i.e. would occupy 50% width of the viewport.

These properties ensure the modal can scale up or down and be responsive.

Making use of the modal component

1import React, { useState } from 'react';
2import Modal from './modal/modal';
3import './App.css';
4
5function App() {
6 const [status, setStatus] = useState(false);
7 return (
8 <div>
9 { status && (<Modal closeModal={() => setStatus(false)}> <p>The content of the modal</p></Modal>)}
10 <div className="container">
11 <h2>This is the page content</h2>
12 <button onClick={() => setStatus(true)}>Open Modal</button>
13 </div>
14
15 </div>
16 );
17}
18
19export default App;

From the above, we rendered the Modal component conditionally. Onclick of the button it changes the status of the modal and renders the modal component.

The function to close the modal is then passed as props into the Modal component as closeModal.

FINAL OUTPUT

Alt Text


Written by Adeyemi Adekorede
You can follow him on Twitter