Documentation
Overlay Components
Modal

Modal

Accessible modal dialog component and global modals provider for React. This package is an enhanced version of react-modal (opens in a new tab).

Features

  • React Portal
  • Global Modals Providers
  • Hooks to control modals
  • Accessibility

Installation

Install the package

npm i @start-base/react-modal

Import the component

import { Modal } from '@start-base/react-modal';

Usages

The primary documentation for Modal component is the react-modal (opens in a new tab), which describes the API and gives examples of its usage.

Next.js example can show all the features and how to use them.

To style the modal, you can utilize the className and overlayClassName props. When it comes to Next.js client-side rendering, you can re-export components with a comment indicating the use of the use client approach.

'use client';
import {
  Modal as ReactModal,
  GlobalModals,
  ModalProvider,
  useModal,
} from '@start-base/react-modal';
 
import styles from './Modal.module.css';
 
const Modal = ({ ...props }) => (
  <ReactModal
    appElement="html"
    {...props}
    className={styles.modal}
    overlayClassName={styles.overlay}
  />
);
 
export { Modal, GlobalModals, ModalProvider, useModal };

Components

<Modal />

The Modal component is the main component of the react-modal library. It can either be a local modal if its state is managed inside its parent, or a global modal if it is wrapped in a GlobalModals component.

<GlobalModals />

The GlobalModals component is a wrapper for <Modal /> components that allows you to manage your modals globally. This method allows you to open and close modals from anywhere in your application. It is meant to be used in conjunction with the useModal hook.

Since the state of the modals inside GlobalModals is managed globally, each requires a unique identifier for the hook to manage its state. This unique identifier is passed as the name prop.

This example creates a series of modals wrapped in GlobalModals that can be opened and closed from anywhere in the application. But, for this to work, we need ModalProvider to be set up in our application.

Providers

<ModalProvider />

The ModalProvider component is a wrapper for GlobalModals that allows you to manage your modals globally. This method allows you to open and close modals from anywhere in your application.

import { Inter } from 'next/font/google';
import { ModalProvider } from '@start-base/react-modal';
 
const inter = Inter({ subsets: ['latin'] });
 
export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
};
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ModalProvider>{children}</ModalProvider>
      </body>
    </html>
  );
}

Now any button that triggers openModal, which comes with useModal hook, can be used to open the modals.

Hooks

useModal

The useModal custom hook provides several useful functions and properties for managing global modals.

modals

The modals string array of useModal hook contains the names of global modals that currently exist.

import { useModal } from '@start-base/react-modal';
 
const { modals } = useModal();
 
console.log(modals); // ["modal-1", "modal-2"]

openedModals

The openedModals object of useModal hook contains the names of the global modals as keys and their state as boolean values.

import { useModal } from '@start-base/react-modal';
 
const { openedModals } = useModal();
 
console.log(openedModals); // { "modal-1": true, "modal-2": false }

openModal

The openModal function of useModal hook opens and optionally stores properties to a global modal. The string passed to this function must match the name property of a given global modal.

The stored properties can be accessed and used with modalProps object of useModal hook.

import { useModal } from '@start-base/react-modal';
 
function MyComponent() {
  const { openModal } = useModal();
 
  function handleDelete() {
    console.log('Deleting modal-1');
  }
 
  return (
    <button onClick={() => openModal('modal-1', { callback: handleDelete })}>
      Open modal-1
    </button>
  );
}
Syntax
openModal(modalName: string)
openModal(modalName: string, modalProps: Record<string, any>)
Parameters

modalName

The name of the modal that will be opened. This string must match the name property of a given global modal.

modalProps Optional

The object to be used as the modal's properties when accessing it using modalProps. This object serves to attach any kind of extra value or function that a modal might need.

closeModal

The closeModal function of useModal hook is used to close a global modal. The string passed to this function must match the name property of a given global modal.

import { useModal } from '@start-base/react-modal';
 
function MyComponent() {
  const { closeModal } = useModal();
 
  return <button onClick={() => closeModal('modal-1')}>Close modal-1</button>;
}

modalProps

The modalProps object of useModal hook contains all values passed to each global modal when opened using openModal function. It can be used to read extra values or run functions attached to a specific global modal.

import { useModal } from '@start-base/react-modal';
 
function MyComponent() {
  const { modalProps, closeModal } = useModal();
 
  console.log(modalProps); // { "modal-1": { callback: () => handleDelete() } }
 
  function handleClose() {
    modalProps['modal-1']?.handleDelete();
    closeModal('modal-1');
  }
 
  return <button onClick={handleClose}>Close modal-1</button>;
}

Styling and Animation

As mentioned in the usage section, you can style the modal using the className and overlayClassName props. For closing animations, you can use closeTimeoutMS prop to delay the closing of the modal.

The following is an example of custom styling and animation.

Styling Modal

.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.8);
  padding: 2rem;
  overflow: auto;
  outline: none;
  border-radius: 10px;
  background-color: var(--black);
  box-shadow:
    0 1px 5px rgba(0, 0, 0, 0.2),
    0 1px 10px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  color: var(--white);
  opacity: 0;
  transition:
    opacity 0.3s ease,
    transform 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
 
  @media (max-width: 768px) {
    max-width: 90%;
  }
}
 
.modal[class~='ReactModal__Content--after-open'] {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}
 
.modal[class~='ReactModal__Content--before-close'] {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.8);
}

Styling Modal overlay

.overlay {
  position: fixed;
  inset: 0;
  background-color: rgba(0, 0, 0, 0);
  transition: background-color 0.3s ease;
}
 
.overlay[class~='ReactModal__Overlay--after-open'] {
  background-color: rgba(0, 0, 0, 0.5);
}
 
.overlay[class~='ReactModal__Overlay--before-close'] {
  background-color: rgba(0, 0, 0, 0);
}