4 steps to set up global modals in React

Learn how to create interactive pop-up windows in a React web app.
66 readers like this.
Digital creative of a browser on the internet

A modal dialog is a window that appears on top of a web page and requires a user's interaction before it disappears. React has a couple of ways to help you generate and manage modals with minimal coding.

If you create them within a local scope, you must import modals into each component and then create a state to manage each modal's opening and closing status.

By using a global state, you don't need to import modals into each component, nor do you have to create a state for each. You can import all the modals in one place and use them anywhere.

In my opinion, the best way to manage modal dialogs in your React application is globally by using a React context rather than a local state.

How to create global modals

Here are the steps (and code) to set up global modals in React. I'm using Patternfly as my foundation, but the principles apply to any project.

1. Create a global modal component

In a file called GlobalModal.tsx, create your modal definition:

import React, { useState, createContext, useContext } from 'react';
import { CreateModal, DeleteModal,UpdateModal } from './components';

export const MODAL_TYPES = {
CREATE_MODAL:”CREATE_MODAL”,
 DELETE_MODAL: “DELETE_MODAL”,
 UPDATE_MODAL: “UPDATE_MODAL”
};

const MODAL_COMPONENTS: any = {
 [MODAL_TYPES.CREATE_MODAL]: CreateModal,
 [MODAL_TYPES.DELETE_MODAL]: DeleteModal,
 [MODAL_TYPES.UPDATE_MODAL]: UpdateModal
};

type GlobalModalContext = {
 showModal: (modalType: string, modalProps?: any) => void;
 hideModal: () => void;
 store: any;
};

const initalState: GlobalModalContext = {
 showModal: () => {},
 hideModal: () => {},
 store: {},
};

const GlobalModalContext = createContext(initalState);
export const useGlobalModalContext = () => useContext(GlobalModalContext);

export const GlobalModal: React.FC<{}> = ({ children }) => {
 const [store, setStore] = useState();
 const { modalType, modalProps } = store || {};

 const showModal = (modalType: string, modalProps: any = {}) => {
   setStore({
     ...store,
     modalType,
     modalProps,
   });
 };

 const hideModal = () => {
   setStore({
     ...store,
     modalType: null,
     modalProps: {},
   });
 };

 const renderComponent = () => {
   const ModalComponent = MODAL_COMPONENTS[modalType];
   if (!modalType || !ModalComponent) {
     return null;
   }
   return <ModalComponent id="global-modal" {...modalProps} />;
 };

 return (
   <GlobalModalContext.Provider value={{ store, showModal, hideModal }}>
     {renderComponent()}
     {children}
   </GlobalModalContext.Provider>
 );
};

In this code, all dialog components are mapped with the modal type. The showModal and hideModal functions are used to open and close dialog boxes, respectively.

The showModal function takes two parameters: modalType and modalProps. The modalProps parameter is optional; it is used to pass any type of data to the modal as a prop.

The hideModal function doesn't have any parameters; calling it causes the current open modal to close.

2. Create modal dialog components

In a file called CreateModal.tsx, create a modal:

import React from "react";
import { Modal, ModalVariant, Button } from "@patternfly/react-core";
import { useGlobalModalContext } from "../GlobalModal";

export const CreateModal = () => {
 const { hideModal, store } = useGlobalModalContext();
 const { modalProps } = store || {};
 const { title, confirmBtn } = modalProps || {};

 const handleModalToggle = () => {
   hideModal();
 };

 return (
   <Modal
     variant={ModalVariant.medium}
     title={title || "Create Modal"}
     isOpen={true}
     onClose={handleModalToggle}
     actions={[
       <Button key="confirm" variant="primary" onClick={handleModalToggle}>
         {confirmBtn || "Confirm button"}
       </Button>,
       <Button key="cancel" variant="link" onClick={handleModalToggle}>
         Cancel
       </Button>
     ]}
   >
     Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
     tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
     veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
     commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
     velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
     cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
     est laborum.
   </Modal>
 );
};

This has a custom hook, useGlobalModalContext, that provides store object from where you can access all the props and the functions showModal and hideModal. You can close the modal by using the hideModal function.

To delete a modal, create a file called DeleteModal.tsx:

import React from "react";
import { Modal, ModalVariant, Button } from "@patternfly/react-core";
import { useGlobalModalContext } from "../GlobalModal";

export const DeleteModal = () => {
 const { hideModal } = useGlobalModalContext();

 const handleModalToggle = () => {
   hideModal();
 };

 return (
   <Modal
     variant={ModalVariant.medium}
     title="Delete Modal"
     isOpen={true}
     onClose={handleModalToggle}
     actions={[
       <Button key="confirm" variant="primary" onClick={handleModalToggle}>
         Confirm
       </Button>,
       <Button key="cancel" variant="link" onClick={handleModalToggle}>
         Cancel
       </Button>
     ]}
   >
     Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
     tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
     veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
     commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
     velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
     cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
     est laborum.
   </Modal>
 );
};

To update a modal, create a file called UpdateModal.tsx and add this code:

import React from "react";
import { Modal, ModalVariant, Button } from "@patternfly/react-core";
import { useGlobalModalContext } from "../GlobalModal";

export const UpdateModal = () => {
 const { hideModal } = useGlobalModalContext();

 const handleModalToggle = () => {
   hideModal();
 };

 return (
   <Modal
     variant={ModalVariant.medium}
     title="Update Modal"
     isOpen={true}
     onClose={handleModalToggle}
     actions={[
       <Button key="confirm" variant="primary" onClick={handleModalToggle}>
         Confirm
       </Button>,
       <Button key="cancel" variant="link" onClick={handleModalToggle}>
         Cancel
       </Button>
     ]}
   >
     Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
     tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
     veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
     commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
     velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
     cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
     est laborum.
   </Modal>
 );
};

3. Integrate GlobalModal into the top-level component in your application

To integrate the new modal structure you've created into your app, you just import the global modal class you've created. Here's my sample App.tsx file:

import "@patternfly/react-core/dist/styles/base.css";
import "./fonts.css";
import { GlobalModal } from "./components/GlobalModal";
import { AppLayout } from "./AppLayout";

export default function App() {
 return (
   <GlobalModal>
     <AppLayout />
   </GlobalModal>
 );
}

App.tsx is the top-level component in your app, but you can add another component according to your application's structure. However, make sure it is one level above where you want to access modals.

GlobalModal is the root-level component where all your modal components are imported and mapped with their specific modalType.

4. Select the modal's button from the AppLayout component

Adding a button to your modal with AppLayout.js:

import React from "react";
import { Button, ButtonVariant } from "@patternfly/react-core";
import { useGlobalModalContext, MODAL_TYPES } from "./components/GlobalModal";

export const AppLayout = () => {
 const { showModal } = useGlobalModalContext();

 const createModal = () => {
   showModal(MODAL_TYPES.CREATE_MODAL, {
     title: "Create instance form",
     confirmBtn: "Save"
   });
 };

 const deleteModal = () => {
   showModal(MODAL_TYPES.DELETE_MODAL);
 };

 const updateModal = () => {
   showModal(MODAL_TYPES.UPDATE_MODAL);
 };

 return (
   <>
     <Button variant={ButtonVariant.primary} onClick={createModal}>
       Create Modal
     </Button>
     <br />
     <br />
     <Button variant={ButtonVariant.primary} onClick={deleteModal}>
       Delete Modal
     </Button>
     <br />
     <br />
     <Button variant={ButtonVariant.primary} onClick={updateModal}>
       Update Modal
     </Button>
   </>
 );
};

There are three buttons in the AppLayout component: create modal, delete modal, and update modal. Each modal is mapped with the corresponding modalType: CREATE_MODAL, DELETE_MODAL, or UPDATE_MODAL.

Use global dialogs

Global modals are a clean and efficient way to handle dialogs in React. They are also easier to maintain in the long run. The next time you set up a project, keep these tips in mind.

If you'd like to see the code in action, I've included the complete application I created for this article in a sandbox.

What to read next
User profile image.
Ajay Pratap is a Full-Stack developer from Agra, Uttar Pradesh, India. Currently working as an Senior Software Engineer at Red Hat India. He has contributed on Red Hat AMQ Online and currently contributing on Red Hat Managed Kafka Services Micro Frontends application. An open source enthusiast and contributor.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.