Modals are one of the most ubiquitous UI elements on the web. In this post we’re going to implement a basic modal component in React. Here’s a summary of the steps we’ll take:
- Create a Dashboard component which holds state and an open button
- Create a Modal component which renders children and holds a close button
- Display the Modal component upon clicking open
- Close the Modal component upon clicking close
Let’s begin with getting our Dashboard component to render with the following code:
import React, { Component } from "react"; import ReactDOM from "react-dom"; class Dashboard extends Component { state = { show: false }; showModal = () => { this.setState({ show: true }); }; hideModal = () => { this.setState({ show: false }); }; render() { return ( <main> <h1>React Modal</h1> <button type="button" onClick={this.showModal}> open </button> </main> ); } } const container = document.createElement("div"); document.body.appendChild(container); ReactDOM.render(<Dashboard />, container);
Nothing new to see here. We’re simply creating a Dashboard component which has a show
state. This state is togglable via the showModal
and hideModal
class properties, for which each will have their own button. In the example above, the Dashboard button’s onClick
handler will toggle the show
state to true.
Next, we’ll build out the Modal component:
Modal.js
const Modal = ({ handleClose, show, children }) => { const showHideClassName = show ? "modal display-block" : "modal display-none"; return ( <div className={showHideClassname}> <section className="modal-main"> {children} <button onClick={handleClose}>close</button> </section> </div> ); };
Here things get a little bit more involved. The Modal component we’ve built will receive handleClose
, show
, and children
down as props from *Dashboard. There’s a showHideClassName
variable which will either display the Modal or not by means of checking the value of show
. If show
is true, the top level div JSX element will have a showHideClassname
of modal display-block
, otherwise, it will be modal display-none
.
We are also rendering the children of Modal, and setting up a close button, which has the onClick
handler of handleClose
, which will set show
in Dashboard to false.
We’ll need to incorporate this Modal component in the Dashboard component like so:
import React, { Component } from "react"; import ReactDOM from "react-dom"; class Dashboard extends Component { state = { show: false }; showModal = () => { this.setState({ show: true }); }; hideModal = () => { this.setState({ show: false }); }; render() { return ( <main> <h1>React Modal</h1> <Modal show={this.state.show} handleClose={this.hideModal}> <p>Modal</p> <p>Data</p> </Modal> <button type="button" onClick={this.showModal}> open </button> </main> ); } } const container = document.createElement("div"); document.body.appendChild(container); ReactDOM.render(<Dashboard />, container);
All we’ve done is added Modal into the Dashboard component’s render method and passed down show
and handleClose
as props. Additionally there are now a couple of paragraph tags which will exist on the Modal’s this.props.children
property.
With this, we have everything we need to style things up to have a functional modal:
.modal { position: fixed; top: 0; left: 0; width:100%; height: 100%; background: rgba(0, 0, 0, 0.6); } .modal-main { position:fixed; background: white; width: 80%; height: auto; top:50%; left:50%; transform: translate(-50%,-50%); } .display-block { display: block; } .display-none { display: none; }
All it does is create a center-aligned white box with a black background after its alpha levels have been adjusted for transparency.
Note that our Modal component is very basic and doesn't offer any affordances for accessibility (a11y). We will revisit and build upon this component in a future post.
Here's what our Modal looks like in action:
And here's a working Codepen demo.