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);
}