Reusable Custom Modal With React Js
The idea behind this tutorial is to the have a wrapping element which provides the styling that wraps itself around any content we want to show. i use this alot in most of my react project. here is a pictorial example of what am talking about (just like a bootstrap modal)
the above is a picture from one of my open source project built with react(available on github)
First and foremost let's install React with npm init react-app my-app
i won’t go into too much details about creating a react app in this tutorial, as i expect you to have the knowledge.
first and foremost i will create Modal.js in a UI folder (the structure of your folder is dependent on you), we will also need a Backdrop.js in the UI folder too and that can be reusable in other things you want to do
Here is the Modal.js code. it is going to be a functional component without any state attached to it. it just receives some props and return some JSX with a div wrapped around props.children so as to be able to receive any content, component, some text that is totally up to us, we can pass anything in there
import React from 'react';
const modal = props => {
return (
<div>
{props.children}
</div>
);
};
export default modal;
and of course the wrapping div should receive some styling to have a modal feeling, so am go create a new modal.module.css file, you can find the css code i used in creating the modal below
with that done, you can import the class from the modal.module.css to the modal.js,
import React from 'react';
import classes from 'Modal.module.css';
const modal = props => {
return (
<div className={classes.Modal}>
{props.children}
</div>
);
};
export default modal;
so you can add the modal.js wherever you want to display it. i will be importing mine to the App.js file
import Modal from '../src/UI/Modal/Modal'
and
<Modal>
<div
style={{color:'black'}}
>
The Best Has Happened To ME
</div>
</Modal>
so i have something that looks like this
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Modal from '../src/UI/Modal/Modal'
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<Modal>
<div
style={{color:'black'}}
>
The Best Has Happened To ME
</div>
</Modal>
</header>
</div>
);
}
}
export default App;
reloading the page, we will have the Modal loaded on page load
The next step is to make sure we don’t always show the modal, but we can show the modal once we click Learn React
we need to add a state to determine if the Learn React Link was clicked
state={
modalToggle: false
}
i will add a new method called modalHandler, which should be triggered when we click on the Learn React
modalHandler = (e) => {
e.preventDefault(); //i added this to prevent the default behavior
this.setState({
modalToggle: true
})
}
Now i can conditionally render the Modal and since we added
transition: all 0.3s ease-out;
to the modal.module.css, it add a bit of animation when the Modal is shown , so let’s take advantage of it
So lets pass a Show property to the Modal we imported in the App.js file and bind it to the modalToggle state. only if the modalToggle is true the Modal should be visible
<Modal show={this.state.modalToggle}>
<div
style={{color:'black'}}
>
The Best Has Happened To ME
</div>
</Modal>
Let’s head over to the modal.js and adjust the code, so the Modal can react to the changes on the show property
i added a new inline style to control the opacity and the transform property
<div
className={classes.Modal}
style={{
transform:props.show ? 'translateY(0)' : 'translateY(-100vh)',
opacity : props.show ? 1 : 0
}}
>
{props.children}
</div>
Reload the page and click on Learn React, The modal should slide in.
Now let’s add a backdrop and when we click on the backdrop, it should dismiss the modal.
Now head over to your backdrop.js file, it is a simple component and doesn’t contain much, we just have to check if the show props is true then return a transparent div or null if false, likewise create a Backdrop.module.css, import it to the Backdrop.js file, your code should look like this
import React from 'react';
import classes from './Backdrop.module.css';
const Backdrop = (props) => (
props.show ? <div className={classes.Backdrop} ></div> : null
)
export default Backdrop
Now import the backdrop.js to the modal.js since they are closely connected, if the modal is shown, the backdrop should be shown
import Backdrop from '../Backdrop/Backdrop';
configure the show properties on the backdrop cause it is expected, and since we have the show properties available in the props we simply pass it to the Backdrop
const modal = props => {
return (
<>
<Backdrop show={props.show} />
....
</>
);
};
Now let’s make sure we can click this backdrop too, for that, we need to add a click listener on the backdrop.js on the div
const Backdrop = (props) => (
props.show ? <div className={classes.Backdrop} onClick={props.clicked}></div> : null
)
Let’s go back to the modal.js and provide a clicked property to trigger a function that will close the modal when clicked
const modal = props => {
return (
<>
<Backdrop show={props.show} clicked={props.modalClosed} />
.....
</>
);
};
modalClosed is now a property we have to add to the Modal property in our App.js file, head over to App.js and add modalClose property to the imported Modal
<Modal show={this.state.modalToggle} modalClosed={this.modalHandler}>
if you observe, the modalClose is set to trigger the modalHandler function, yes that is correct, i made a slight change the function to set modelToggle to the opposite of modelToggle
modalHandler = (e) => {
e.preventDefault();
this.setState({
modalToggle: !this.state.modalToggle
})
}
Now you have a working reusable modal with react