Skip to main content

Modal

The Modal component is a flexible overlay dialog component that displays content in a floating window. It provides backdrop support, multiple positioning options, various sizes, and customizable styling for creating engaging user interactions.

Overview

The Modal component is designed to provide flexible dialog functionality with:

  • Multiple positioning options (center, top, bottom, left, right)
  • Various size configurations
  • Backdrop blur effects
  • Click-outside-to-close functionality
  • Header, body, and footer sections
  • Close button integration
  • Responsive design with proper z-index management

Basic Usage

import Modal from '@/components/molecules/Modal'
import { Button } from '@/components/atoms'
import { useState } from 'react'

function MyComponent() {
const [isOpen, setIsOpen] = useState(false)

return (
<>
<Button className='btn-primary' onClick={() => setIsOpen(true)}>
Open Modal
</Button>

<Modal.Dialog open={isOpen} onClose={() => setIsOpen(false)}>
<Modal.Header closeButton onClose={() => setIsOpen(false)}>
<Modal.Title>Modal Title</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Modal content goes here.</p>
</Modal.Body>
<Modal.Footer>
<Button className='btn-primary outlined' onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button className='btn-primary'>Save</Button>
</Modal.Footer>
</Modal.Dialog>
</>
)
}

Props

Modal.Dialog Props

PropTypeDefaultDescription
openboolean-Whether the modal is currently open
onClosefunction-Callback function when modal should close
childrenReactNode-The content to display in the modal
sizestring'max-w-md'CSS class for modal width
backdropstring-CSS class for backdrop styling
positionstring'center'Position of modal ('center', 'top', 'bottom', 'left', 'right')
closeOnBackdropbooleanfalseWhether clicking backdrop closes the modal

Modal.Header Props

PropTypeDefaultDescription
childrenReactNode-The content to display in the header
closeButtonboolean-Whether to show close button
onClosefunction-Callback for close button click
classNamestring''Additional CSS classes

Modal.Title Props

PropTypeDefaultDescription
childrenReactNode-The title text
classNamestring''Additional CSS classes

Modal.Body Props

PropTypeDefaultDescription
childrenReactNode-The content to display in the body
classNamestring''Additional CSS classes

Modal.Footer Props

PropTypeDefaultDescription
childrenReactNode-The content to display in the footer
classNamestring''Additional CSS classes

Basic Modal

Simple Modal

<Card>
<h4 className='mb-2'>Basic Modal</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false })}>
Open Modal
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 2, closeOnBackdrop: true })}>
Open close backdrop
</Button>
</div>
</Card>

Complete Modal Structure

<Modal.Dialog
open={!!openModal.id}
size={openModal.size || 'max-w-md'}
closeOnBackdrop={!!openModal.closeOnBackdrop}
backdrop={openModal.backdrop}
position={openModal.position || 'center'}
onClose={() => setOpenModal({})}>
<Modal.Header closeButton onClose={() => setOpenModal({})}>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Modal body text goes here.</p>
</Modal.Body>
<Modal.Footer>
<Button className='btn-primary outlined' onClick={() => setOpenModal({})}>
Close
</Button>
<Button className='btn-primary'>Save changes</Button>
</Modal.Footer>
</Modal.Dialog>

Center Position (Default)

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false })}>
Center
</Button>

Bottom Position

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'bottom' })}>
Bottom
</Button>

Left Position

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'left' })}>
Left
</Button>

Right Position

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'right' })}>
Right
</Button>

Position Examples

<Card>
<h4 className='mb-2'>Modal Position</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false })}>
Center
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'bottom' })}>
Bottom
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'left' })}>
Left
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'right' })}>
Right
</Button>
</div>
</Card>

Small Modal

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-sm' })}>
Small
</Button>

Large Modal

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-lg' })}>
Large
</Button>

Extra Large Modal

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-2xl' })}>
Extra Large
</Button>

Full Width Modal

<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-5xl' })}>
Extra Large
</Button>

Size Examples

<Card>
<h4 className='mb-2'>Modal Size</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-sm' })}>
Small
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-lg' })}>
Large
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-2xl' })}>
Extra Large
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-5xl' })}>
Extra Large
</Button>
</div>
</Card>

Backdrop Options

Default Backdrop

<Modal.Dialog open={isOpen} onClose={() => setIsOpen(false)}>
{/* Modal content */}
</Modal.Dialog>

Blur Backdrop Small

<Modal.Dialog 
open={isOpen}
onClose={() => setIsOpen(false)}
backdrop="backdrop-blur-sm"
closeOnBackdrop={true}>
{/* Modal content */}
</Modal.Dialog>

Blur Backdrop Medium

<Modal.Dialog 
open={isOpen}
onClose={() => setIsOpen(false)}
backdrop="backdrop-blur-md"
closeOnBackdrop={true}>
{/* Modal content */}
</Modal.Dialog>

Blur Backdrop Large

<Modal.Dialog 
open={isOpen}
onClose={() => setIsOpen(false)}
backdrop="backdrop-blur-lg"
closeOnBackdrop={true}>
{/* Modal content */}
</Modal.Dialog>

Backdrop Examples

<Card>
<h4 className='mb-2'>Modal with Blur Backdrop</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 3, closeOnBackdrop: true, backdrop: 'backdrop-blur-sm' })}>
Blur Small
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 4, closeOnBackdrop: true, backdrop: 'backdrop-blur-md' })}>
Blur Medium
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 5, closeOnBackdrop: true, backdrop: 'backdrop-blur-lg' })}>
Blur Large
</Button>
</div>
</Card>

Header with Close Button

<Modal.Header closeButton onClose={() => setIsOpen(false)}>
<Modal.Title>Modal Title</Modal.Title>
</Modal.Header>

Header without Close Button

<Modal.Header>
<Modal.Title>Modal Title</Modal.Title>
</Modal.Header>

Body Content

<Modal.Body>
<p>This is the modal body content.</p>
<p>You can include any React components here.</p>
</Modal.Body>
<Modal.Footer>
<Button className='btn-primary outlined' onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button className='btn-primary'>Save Changes</Button>
</Modal.Footer>

State Management

Using useState

import { useState } from 'react'

const ModalExample = () => {
const [openModal, setOpenModal] = useState({})

const openModalHandler = (config) => {
setOpenModal(config)
}

const closeModalHandler = () => {
setOpenModal({})
}

return (
<>
<Button className='btn-primary' onClick={() => openModalHandler({ id: 1, closeOnBackdrop: true })}>
Open Modal
</Button>

<Modal.Dialog
open={!!openModal.id}
size={openModal.size || 'max-w-md'}
closeOnBackdrop={!!openModal.closeOnBackdrop}
backdrop={openModal.backdrop}
position={openModal.position || 'center'}
onClose={closeModalHandler}>
<Modal.Header closeButton onClose={closeModalHandler}>
<Modal.Title>Modal Title</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Modal content</p>
</Modal.Body>
<Modal.Footer>
<Button className='btn-primary outlined' onClick={closeModalHandler}>
Close
</Button>
<Button className='btn-primary'>Save</Button>
</Modal.Footer>
</Modal.Dialog>
</>
)
}

Examples

Basic Modal

<Card>
<h4 className='mb-2'>Basic Modal</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false })}>
Open Modal
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 2, closeOnBackdrop: true })}>
Open close backdrop
</Button>
</div>
</Card>
<Card>
<h4 className='mb-2'>Modal Position</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false })}>
Center
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'bottom' })}>
Bottom
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'left' })}>
Left
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, position: 'right' })}>
Right
</Button>
</div>
</Card>
<Card>
<h4 className='mb-2'>Modal Size</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-sm' })}>
Small
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-lg' })}>
Large
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-2xl' })}>
Extra Large
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 1, closeOnBackdrop: false, size: 'max-w-5xl' })}>
Extra Large
</Button>
</div>
</Card>
<Card>
<h4 className='mb-2'>Modal with Blur Backdrop</h4>
<div className='space-x-2'>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 3, closeOnBackdrop: true, backdrop: 'backdrop-blur-sm' })}>
Blur Small
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 4, closeOnBackdrop: true, backdrop: 'backdrop-blur-md' })}>
Blur Medium
</Button>
<Button className='btn-primary' onClick={() => setOpenModal({ id: 5, closeOnBackdrop: true, backdrop: 'backdrop-blur-lg' })}>
Blur Large
</Button>
</div>
</Card>

CSS Classes Reference

  • .modal - Base modal wrapper
  • .modal__wrapper - Modal positioning wrapper
  • .modal__wrapper--center - Center positioning
  • .modal__wrapper--top - Top positioning
  • .modal__wrapper--bottom - Bottom positioning
  • .modal__wrapper--left - Left positioning
  • .modal__wrapper--right - Right positioning
  • .modal__container - Modal content container
  • .modal__header - Header section with border
  • .modal__title - Title styling
  • .modal__body - Body content area
  • .modal__footer - Footer section with border

Size Classes

  • max-w-sm - Small modal (384px)
  • max-w-md - Medium modal (448px) - Default
  • max-w-lg - Large modal (512px)
  • max-w-2xl - Extra large modal (672px)
  • max-w-5xl - Full width modal (1024px)

Backdrop Classes

  • backdrop-blur-sm - Small blur effect
  • backdrop-blur-md - Medium blur effect
  • backdrop-blur-lg - Large blur effect

Styling

The Modal component uses Tailwind CSS classes and includes:

  • Fixed Positioning: Full-screen overlay positioning
  • Z-Index Management: Proper layering with z-50
  • Responsive Design: Works on all screen sizes
  • Flexbox Layout: Flexible positioning system
  • Shadow Effects: Drop shadow for depth
  • Border Radius: Rounded corners for modern appearance
  • Backdrop Blur: Configurable blur effects

Accessibility

The Modal component includes accessibility features:

  • Focus Management: Proper focus trapping
  • Keyboard Navigation: ESC key to close
  • Screen Reader Support: ARIA labels and semantic structure
  • Backdrop Click: Click outside to close (when enabled)
  • Close Button: Accessible close button with proper labeling

Best Practices

  1. Always provide an onClose handler for proper cleanup
  2. Use appropriate sizes for different content types
  3. Consider mobile users with responsive positioning
  4. Include close functionality in footer actions
  5. Use backdrop blur for better visual separation
  6. Test keyboard navigation for accessibility compliance

Common Use Cases

  • Confirmation dialogs: User confirmations and alerts
  • Form modals: Data entry and editing forms
  • Content previews: Image, video, or document previews
  • Settings panels: Configuration and preferences
  • User onboarding: Welcome and tutorial content
  • Button - Used for modal triggers and actions
  • ModalBackdrop - Backdrop overlay component
  • ModalCloseButton - Close button component
  • Card - Often used as a container for modal examples