Skip to content

Modal

Modal

A modal dialog component for displaying content in an overlay.

Import

import { Modal } from '@primitivekit/react';

Basic Usage

import { useState } from 'react';

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

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open Modal</Button>
      
      <Modal 
        isOpen={isOpen} 
        onClose={() => setIsOpen(false)}
        title="Modal Title"
      >
        <p>Modal content goes here</p>
      </Modal>
    </>
  );
}

Sizes

<Modal size="small" isOpen={isOpen} onClose={onClose}>
  Small modal
</Modal>

<Modal size="medium" isOpen={isOpen} onClose={onClose}>
  Medium modal
</Modal>

<Modal size="large" isOpen={isOpen} onClose={onClose}>
  Large modal
</Modal>

<Modal size="full" isOpen={isOpen} onClose={onClose}>
  Full screen modal
</Modal>

With Footer

<Modal 
  isOpen={isOpen} 
  onClose={onClose}
  title="Confirm Action"
  footer={
    <>
      <Button variant="outline" onClick={onClose}>
        Cancel
      </Button>
      <Button variant="primary" onClick={handleConfirm}>
        Confirm
      </Button>
    </>
  }
>
  <p>Are you sure you want to proceed?</p>
</Modal>

Centered

<Modal 
  isOpen={isOpen} 
  onClose={onClose}
  centered
>
  Centered modal
</Modal>

Close Options

<Modal 
  isOpen={isOpen} 
  onClose={onClose}
  closeOnOverlayClick={false}
  closeOnEscape={false}
  showCloseButton={false}
>
  Cannot be closed by clicking outside or pressing Escape
</Modal>

Props

PropTypeDefaultDescription
isOpenbooleanrequiredModal open state
onClosefunctionrequiredClose handler
titlestring | ReactNode-Modal title
footerReactNode-Modal footer content
size'small' | 'medium' | 'large' | 'full''medium'Modal size
centeredbooleantrueCenter vertically
showCloseButtonbooleantrueShow close button
closeOnOverlayClickbooleantrueClose on overlay click
closeOnEscapebooleantrueClose on Escape key
preventScrollbooleantruePrevent body scroll
childrenReactNoderequiredModal content
classNamestring-Additional CSS classes
styleModalCSSVariables-CSS variable overrides

Customization

<Modal
  isOpen={isOpen}
  onClose={onClose}
  style={{
    '--modal-bg-color': 'rgba(255, 255, 255, 1)',
    '--modal-border-radius': '16px',
    '--modal-box-shadow': '0 20px 60px rgba(0, 0, 0, 0.3)',
    '--modal-overlay-bg-color': 'rgba(0, 0, 0, 0.7)',
    '--modal-max-width': '600px',
  }}
>
  Custom styled modal
</Modal>

Examples

Confirmation Dialog

function DeleteConfirmation({ isOpen, onClose, onConfirm }) {
  return (
    <Modal
      isOpen={isOpen}
      onClose={onClose}
      title="Delete Item"
      footer={
        <>
          <Button variant="outline" onClick={onClose}>
            Cancel
          </Button>
          <Button variant="danger" onClick={onConfirm}>
            Delete
          </Button>
        </>
      }
    >
      <p>Are you sure you want to delete this item? This action cannot be undone.</p>
    </Modal>
  );
}

Form Modal

function EditProfileModal({ isOpen, onClose, user }) {
  const [formData, setFormData] = useState(user);

  const handleSubmit = async () => {
    await updateProfile(formData);
    onClose();
  };

  return (
    <Modal
      isOpen={isOpen}
      onClose={onClose}
      title="Edit Profile"
      size="large"
      footer={
        <>
          <Button variant="outline" onClick={onClose}>
            Cancel
          </Button>
          <Button variant="primary" onClick={handleSubmit}>
            Save Changes
          </Button>
        </>
      }
    >
      <Stack spacing="medium">
        <Input
          label="Name"
          value={formData.name}
          onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        />
        <Input
          label="Email"
          type="email"
          value={formData.email}
          onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        />
        <Textarea
          label="Bio"
          value={formData.bio}
          onChange={(e) => setFormData({ ...formData, bio: e.target.value })}
        />
      </Stack>
    </Modal>
  );
}

Accessibility

  • ✅ Focus trap within modal
  • ✅ Focus returns to trigger on close
  • ✅ Escape key to close
  • ✅ ARIA role=“dialog”
  • ✅ aria-modal=“true”
  • ✅ aria-labelledby for title
  • ✅ Body scroll lock
  • ✅ Screen reader announcements

Related Components