or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-react-modal

Accessible modal dialog component for React.JS applications with comprehensive ARIA support and customization options.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/react-modal@3.16.x

To install, run

npx @tessl/cli install tessl/npm-react-modal@3.16.0

index.mddocs/

React Modal

React Modal is an accessible modal dialog component for React.JS applications. It provides comprehensive ARIA accessibility support, keyboard navigation, focus management, and extensive customization options for creating modal dialogs that work seamlessly with screen readers and assistive technologies.

Package Information

  • Package Name: react-modal
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install react-modal

Core Imports

import Modal from 'react-modal';

For CommonJS:

const Modal = require('react-modal');

Basic Usage

import React, { useState } from 'react';
import Modal from 'react-modal';

// Set app element for accessibility (required)
Modal.setAppElement('#yourAppElement');

function App() {
  const [modalIsOpen, setIsOpen] = useState(false);

  function openModal() {
    setIsOpen(true);
  }

  function closeModal() {
    setIsOpen(false);
  }

  return (
    <div>
      <button onClick={openModal}>Open Modal</button>
      <Modal
        isOpen={modalIsOpen}
        onRequestClose={closeModal}
        contentLabel="Example Modal"
      >
        <h2>Hello Modal</h2>
        <button onClick={closeModal}>Close</button>
      </Modal>
    </div>
  );
}

Architecture

React Modal uses a portal-based architecture that renders the modal outside the normal React component tree:

  • Portal Rendering: Uses React portals to render modals at the document body level, avoiding z-index issues
  • Accessibility Layer: Implements ARIA standards with focus management and screen reader support
  • Event Management: Handles keyboard navigation, overlay clicks, and focus trapping
  • Style System: Supports both inline styles and CSS classes with state-based class names

Capabilities

Modal Component

The main Modal component that renders an accessible dialog with overlay and content areas.

/**
 * Accessible modal dialog component
 */
function Modal(props: ModalProps): JSX.Element;

interface ModalProps {
  /** Required: Controls modal visibility */
  isOpen: boolean;
  
  /** Styling props */
  style?: {
    content?: React.CSSProperties;
    overlay?: React.CSSProperties;
  };
  className?: string | ClassNameConfig;
  overlayClassName?: string | ClassNameConfig;
  
  /** Portal and DOM props */
  portalClassName?: string;
  bodyOpenClassName?: string;
  htmlOpenClassName?: string;
  parentSelector?: () => HTMLElement;
  
  /** Accessibility props */
  appElement?: HTMLElement | HTMLElement[] | NodeList | string;
  ariaHideApp?: boolean;
  role?: string;
  contentLabel?: string;
  aria?: { [key: string]: string };
  
  /** Behavior props */
  shouldFocusAfterRender?: boolean;
  shouldCloseOnOverlayClick?: boolean;
  shouldCloseOnEsc?: boolean;
  shouldReturnFocusAfterClose?: boolean;
  preventScroll?: boolean;
  closeTimeoutMS?: number;
  
  /** Event handlers */
  onAfterOpen?: (options: { overlayEl: Element; contentEl: Element }) => void;
  onAfterClose?: () => void;
  onRequestClose?: (event: React.MouseEvent | React.KeyboardEvent) => void;
  
  /** Refs and custom elements */
  overlayRef?: (instance: HTMLDivElement) => void;
  contentRef?: (instance: HTMLDivElement) => void;
  overlayElement?: (props: any, contentEl: React.ReactElement) => React.ReactElement;
  contentElement?: (props: any, children: React.ReactNode) => React.ReactElement;
  
  /** Additional attributes */
  data?: { [key: string]: string };
  id?: string;
  testId?: string;
  children?: React.ReactNode;
}

interface ClassNameConfig {
  base: string;
  afterOpen: string;
  beforeClose: string;
}

Static Methods

Configuration methods available on the Modal component.

/**
 * Sets the app element for accessibility. Must be called before using modals.
 * @param element - DOM element, selector string, or array of elements to hide from screen readers
 */
Modal.setAppElement(element: HTMLElement | HTMLElement[] | NodeList | string): void;

/**
 * Development-only: Sets custom HTML element creation function for testing (NODE_ENV !== "production")
 * @param fn - Function to create HTML elements
 */
Modal.setCreateHTMLElement?(fn: (name: string) => HTMLElement): void;

Static Properties

Pre-defined styling and constants available on the Modal component.

/**
 * Default styles for modal overlay and content
 */
Modal.defaultStyles: {
  overlay: {
    position: 'fixed';
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    backgroundColor: 'rgba(255, 255, 255, 0.75)';
  };
  content: {
    position: 'absolute';
    top: '40px';
    left: '40px';
    right: '40px';
    bottom: '40px';
    border: '1px solid #ccc';
    background: '#fff';
    overflow: 'auto';
    WebkitOverflowScrolling: 'touch';
    borderRadius: '4px';
    outline: 'none';
    padding: '20px';
  };
};

Styling

Inline Styles

const customStyles = {
  content: {
    top: '50%',
    left: '50%',
    right: 'auto',
    bottom: 'auto',
    marginRight: '-50%',
    transform: 'translate(-50%, -50%)',
  },
};

<Modal
  isOpen={modalIsOpen}
  style={customStyles}
  contentLabel="Centered Modal"
>
  <h2>Centered Content</h2>
</Modal>

CSS Classes

<Modal
  isOpen={modalIsOpen}
  className="modal-content"
  overlayClassName="modal-overlay"
  contentLabel="Styled Modal"
>
  <h2>Custom Styled Modal</h2>
</Modal>

State-based Classes

<Modal
  isOpen={modalIsOpen}
  className={{
    base: 'modal-content',
    afterOpen: 'modal-content--after-open',
    beforeClose: 'modal-content--before-close'
  }}
  overlayClassName={{
    base: 'modal-overlay',
    afterOpen: 'modal-overlay--after-open',
    beforeClose: 'modal-overlay--before-close'
  }}
>
  <h2>Animated Modal</h2>
</Modal>

Accessibility

Required Setup

// Required: Set app element before using any modals
Modal.setAppElement('#root');

// Or with multiple elements
Modal.setAppElement([document.getElementById('root'), document.getElementById('menu')]);

Accessibility Props

<Modal
  isOpen={modalIsOpen}
  contentLabel="User Profile Dialog"  // Required for screen readers
  role="dialog"                       // Default, can be changed
  ariaHideApp={true}                 // Default, hides background content
  shouldFocusAfterRender={true}      // Default, focuses modal on open
  shouldReturnFocusAfterClose={true} // Default, returns focus on close
>
  <h2 id="modal-title">User Profile</h2>
  <div aria-describedby="modal-title">
    Modal content here
  </div>
</Modal>

Event Handling

Close Events

function handleRequestClose(event) {
  // event can be from ESC key or overlay click
  console.log('Modal close requested:', event.type);
  setModalIsOpen(false);
}

<Modal
  isOpen={modalIsOpen}
  onRequestClose={handleRequestClose}
  shouldCloseOnOverlayClick={true}  // Default
  shouldCloseOnEsc={true}          // Default
>
  <h2>Closeable Modal</h2>
</Modal>

Lifecycle Events

function handleAfterOpen({ overlayEl, contentEl }) {
  // Modal is now fully open and accessible
  console.log('Modal opened', { overlayEl, contentEl });
}

function handleAfterClose() {
  // Modal is completely closed and removed from DOM
  console.log('Modal closed');
}

<Modal
  isOpen={modalIsOpen}
  onAfterOpen={handleAfterOpen}
  onAfterClose={handleAfterClose}
>
  <h2>Modal with Lifecycle Handlers</h2>
</Modal>

Custom Elements

Custom Overlay and Content

const customOverlay = (props, contentEl) => (
  <div {...props} className="custom-overlay">
    {contentEl}
  </div>
);

const customContent = (props, children) => (
  <div {...props} className="custom-content">
    <header>Modal Header</header>
    <main>{children}</main>
    <footer>Modal Footer</footer>
  </div>
);

<Modal
  isOpen={modalIsOpen}
  overlayElement={customOverlay}
  contentElement={customContent}
>
  <p>Content goes in the main section</p>
</Modal>

Animation and Transitions

CSS Transitions

<Modal
  isOpen={modalIsOpen}
  closeTimeoutMS={200}  // Wait 200ms before unmounting
  className={{
    base: 'modal',
    afterOpen: 'modal--after-open',
    beforeClose: 'modal--before-close'
  }}
>
  <h2>Animated Modal</h2>
</Modal>

Corresponding CSS:

.modal {
  opacity: 0;
  transition: opacity 200ms;
}

.modal--after-open {
  opacity: 1;
}

.modal--before-close {
  opacity: 0;
}

Advanced Configuration

Portal Customization

<Modal
  isOpen={modalIsOpen}
  portalClassName="custom-portal"
  parentSelector={() => document.getElementById('modal-root')}
  bodyOpenClassName="body-modal-open"
  htmlOpenClassName="html-modal-open"
>
  <h2>Custom Portal Modal</h2>
</Modal>

Refs and DOM Access

let overlayRef;
let contentRef;

<Modal
  isOpen={modalIsOpen}
  overlayRef={ref => overlayRef = ref}
  contentRef={ref => contentRef = ref}
  onAfterOpen={() => {
    // Direct DOM access available
    console.log('Overlay element:', overlayRef);
    console.log('Content element:', contentRef);
  }}
>
  <h2>Modal with Refs</h2>
</Modal>

Testing Support

<Modal
  isOpen={modalIsOpen}
  testId="user-profile-modal"
  contentLabel="User Profile"
>
  <h2>User Profile Modal</h2>
  <p>This modal can be found by test frameworks using data-testid="user-profile-modal"</p>
</Modal>