Creating a Reusable Modal Dialog in React Bootstrap
Motivation
A modal dialog box is a graphical user interface element that is commonly used in programming to display information or prompt the user for input. It is a type of window that requires the user to interact with it before they can return to other parts of the application. Modal dialog boxes are useful when developers want to interrupt the user's workflow to gather input or display critical information that requires immediate attention. They can be used for a variety of purposes, such as displaying error messages, asking the user to confirm an action, or displaying a form for data entry.
For my fifth project for Code Institute, I built a recipe sharing site using React Bootstrap components. When the user clicked on an icon to delete a recipe, I wanted a popup dialog to appear asking them to confirm their choices. In this article, I show you how to implement a reuseable modal dialog component in React to ask for confirmation before executing a delete function.
- I assume you have React application running and the Boostrap react library installed.
- The focus of this article is on the implementation of a reusable component, not style. The component we create will have the default styling.
- We are not worried about folder structure.
Creating the Modal Component
The first thing we want to do is create a file called ModalAlert.jsx and store it in an appropriate folder in your project - ie wherever you store files for your components and add the following. (I have exaggerated spacing for readability.)
// (1) The imports import React from 'react'; import Button from 'react-bootstrap/Button'; import Modal from 'react-bootstrap/Modal'; //(2) props function ModalAlert({show, handleClose, onConfirm, title, message, buttonLabel}) { return ( //(3) Declare Modal component. <Modal show={show} onHide={handleClose} onClose={handleClose}> //(4) Define the Header <Modal.Header> <Modal.Title>{title}</Modal.Title> </Modal.Header> //(5) The body of our modal. <Modal.Body> {message} </Modal.Body> // (6) Footer with buttons <Modal.Footer> <Button onClick={handleClose}> Close </Button> <Button onClick={onConfirm}> {buttonLabel} </Button> </Modal.Footer> </Modal> ) } export default ModalAlert
Let us look at this one section at a time. (1) is just the import statements. Nothing there.
In part (2) we have function ModalAlert({show, handleClose, onConfirm, title, message})
. All we are doing is declaring a functional component called ModalAlert and passing it some props. Let's example what those props are. Remember, that these props come from the parent.
show
This is a boolean If true, the dialog will show. If false, it will be hidden.handleClose
is a callback method that will execute when the user clicks on the Close button.onConfirm
is a callback method that will execute when the user clicks on the Delete button. In other words, by clicking on the Delete button the user confirms that they want the item deleted.title
is a string that will be used for the title of the modal.message
is string that will me used to display text to the user in the body of the modal.buttonLabel
is a string to name the button. It can be whatever you want the "confirm" button to say. For example, "Save", "Delete", "Confirm" etc
OK. Props explained let's get to the rest.
In part (3) we have<Modal show={show} onHide={handleClose} onClose={handleClose}>
where we pass down our props to the show, onHide, and onClose properties of the Modal component. show, onHide, and onClose are properties from the React Bootstrap library. Notice that we use the same callback for onHide and onClose.
In part (4) we add a <Modal.Header>
component with a <Modal.Title>
component as a child. In the <Modal.Title>
, we render the title
prop. <Modal.Title>{title}</Modal.Title>
.
In part (5) we add a <Modal.Body>
component which renders the message
prop.
In part (6), we add a <Modal.Footer>
component with two <Button>
components as children. Placing the buttons in the footer will lay them out properly - to the right side of the dialog box.
For each button we pass a callback to its onClick property. We pass our onConfirm
prop to the onClick property for the Delete button and the handleClose
callback to the onClick property of the Close button.
That's it for setting up our component. Now let's use it. This component will get what it needs from the parent.
Using the Modal Component
The first thing to do is to place your modal component into the component tree of wherever you want that modal to be displayed. For example, you might have a component tree like the following excerpt. Remember this is an excerpt and an example. I have left out the rest of the file for clarity and readability.
//Import Statements //Methods and variables <> <Book> <Title /> <Author /> <Description /> <DeleteIcon /> </Book> <ModalAlert show={} handleClose={} onConfirm={} title={} message={} buttonLabel{} /> //Get that component into the tree! </>
OK. we placed our modal component into the tree. Now let us pass it the props it needs.
Start easy. Lets give it the title, message, and buttonLabel data it needs. These are just strings.
<ModalAlert show={} handleClose={} onConfirm={} title={"Confirm Delete"} message={"Delete the Book?"} buttonLabel={"Delete"} />
Now let's set the onConfirm property. This will be a callback. So we must write a function containing the code to execeute when the user confirms the action and pass its name to the property. (Remember in this case it will be clicking on the Delete button.)
const handleDelete = () => { //Code to delete the book. //Remember the delete function is just an example. You can program the buttons to do whatever you want. }; <> <Book> <Title /> <Author /> <Description /> <DeleteIcon /> </Book> <ModalAlert show={} handleClose={} onConfirm={handleDelete} title={"Confirm Delete"} message={"Delete the Book?"} buttonLabel={"Delete"} /> //Get that component into the tree! </>
Now for the hard part. We need a variable which will be a boolean to keep track of whether or not the ModalAlert is to be visible or not. Using a state hook is a good way to do this. We create a state variable called show along with a setShow method and set its initial value to false (since we don't want the dialog to initially be visible.) We can then pass this variable to the show
property of our dialog.
const [show, setShow] = useState(false);
const [show, setShow] = useState(false); const handleDelete = () => { //Code to delete the book. //Remember the delete function is just an example. You can program the buttons to do whatever you want. }; <> <Book> <Title /> <Author /> <Description /> <DeleteIcon /> </Book> <ModalAlert show={show} handleClose={} onConfirm={handleDelete} title={"Confirm Delete"} message={"Delete the Book?"} buttonLabel={"Delete"} /> //Get that component into the tree! </>
We can pass the callback for handleClose now. No need for a separate method. We can do this inline.
const [show, setShow] = useState(false); const handleDelete = () => { //Code to delete the book. //Remember the delete function is just an example. You can program the buttons to do whatever you want. }; <> <Book> <Title /> <Author /> <Description /> <DeleteIcon /> </Book> <ModalAlert show={show} handleClose={() => setShow(false)} // Just set show to false. The dialog will disappear. onConfirm={handleDelete} title={"Confirm Delete"} message={"Delete the Book?"} buttonLabel={"Delete"} /> //Get that component into the tree! </>
We are almost done. But the problem remains, how and do we get your dialog to appear? To make it appear, we call the setShow method like this setShow(true)
. Which will set show
to true and this make the dialog appear. However, when that should be called is up to you. In this case, I would like the dialog to appear when the user clicks on the <DeleteIcon>
component. I would therefore pass the following callback to its onClick method:
<DeleteIcon onClick={()=>setShow(true)}/>
. Our final code would look like this:
const [show, setShow] = useState(false); const handleDelete = () => { //Code to delete the book. //Remember the delete function is just an example. You can program the buttons to do whatever you want. }; <> <Book> <Title /> <Author /> <Description /> <DeleteIcon onClick={()=>setShow(true)}/> </Book> <ModalAlert show={show} handleClose={() => setShow(false)} // Just set show to false. The dialog will disappear. onConfirm={handleDelete} title={"Confirm Delete"} message={"Delete the Book?"} buttonLabel={"Delete"} /> //Get that component into the tree! </>
That is it! To make sure you understand, go through the article one more time to make sure you see how things are connected and when the functions will run. Add a comment if anything is confusing or if you want clarification.