Skip to main content

Modal Component

Accessible dialog boxes with multiple variants, animations, and responsive designs

Overview

The Modal component provides accessible dialog overlays for displaying content above the main page. Modals can be used for forms, confirmations, image galleries, alerts, and any content that requires focused user attention. The component includes full keyboard navigation, focus management, and responsive designs.

🎭 Multiple Variants

Standard dialogs, alerts, image lightboxes, drawers, and bottom sheets for different use cases.

📏 Flexible Sizing

Small, default, large, extra-large, and full-screen aiab-modal sizes with responsive behavior.

✨ Rich Animations

Fade-in, slide-down, zoom-in animations with smooth transitions and backdrop effects.

♿ Full Accessibility

ARIA attributes, focus trapping, keyboard navigation, and screen reader support.

📱 Responsive Design

Adaptive layouts for mobile devices with touch-friendly interactions.

🌙 Dark Mode Ready

Automatic dark mode support with appropriate color schemes and contrast.

Basic Usage

Simple Modal

Basic Modal Example
<!-- Modal Structure -->
<div class="aiab-modal-backdrop" id="aiab-modal-backdrop"></div>
<div class="aiab-modal" id="basic-modal" aria-hidden="true" role="dialog" aria-labelledby="aiab-modal-title">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__header">
      <h2 class="aiab-modal__title" id="aiab-modal-title">Modal Title</h2>
      <button class="aiab-modal__close" aria-label="Close aiab-modal">
        <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
          <path d="M18 6L6 18M6 6l12 12"/>
        </svg>
      </button>
    </div>
    <div class="aiab-modal__body">
      <p>This is the aiab-modal content. You can put any content here including forms, images, or other components.</p>
    </div>
    <div class="aiab-modal__footer">
      <button class="aiab-btn aiab-btn--secondary">Cancel</button>
      <button class="aiab-btn aiab-btn--primary">Confirm</button>
    </div>
  </div>
</div>

Modal with Form

Modal containing a form
<div class="aiab-modal" id="form-modal">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__header">
      <h2 class="aiab-modal__title">Contact Information</h2>
      <button class="aiab-modal__close">×</button>
    </div>
    <div class="aiab-modal__body">
      <form>
        <div class="aiab-form-group">
          <label for="name">Name</label>
          <input type="text" id="name" class="aiab-form-control" required>
        </div>
        <div class="aiab-form-group">
          <label for="email">Email</label>
          <input type="email" id="email" class="aiab-form-control" required>
        </div>
        <div class="aiab-form-group">
          <label for="message">Message</label>
          <textarea id="message" class="aiab-form-control" rows="4"></textarea>
        </div>
      </form>
    </div>
    <div class="aiab-modal__footer">
      <button class="aiab-btn aiab-btn--secondary">Cancel</button>
      <button class="aiab-btn aiab-btn--primary">Send Message</button>
    </div>
  </div>
</div>

Modal Sizes

Different Modal Sizes
<!-- Small Modal -->
<div class="aiab-modal aiab-modal--sm">...</div>

<!-- Default Modal -->
<div class="aiab-modal">...</div>

<!-- Large Modal -->
<div class="aiab-modal aiab-modal--lg">...</div>

<!-- Extra Large Modal -->
<div class="aiab-modal aiab-modal--xl">...</div>

<!-- Full Screen Modal -->
<div class="aiab-modal aiab-modal--full">...</div>

Modal Variants

Alert Modals

Alert Style Modals
<!-- Success Alert Modal -->
<div class="aiab-modal aiab-modal--alert aiab-modal--success">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__body">
      <div class="aiab-modal__icon">
        <svg width="32" height="32" fill="currentColor" viewBox="0 0 20 20">
          <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
        </svg>
      </div>
      <h3 class="aiab-modal__title">Success!</h3>
      <p>Your action was completed successfully.</p>
    </div>
    <div class="aiab-modal__footer aiab-modal__footer--center">
      <button class="aiab-btn aiab-btn--primary">OK</button>
    </div>
  </div>
</div>

Image Modal

Image Lightbox Modal
<div class="aiab-modal aiab-modal--image">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__body">
      <img src="https://picsum.photos/600/400" alt="Description" />
    </div>
    <button class="aiab-modal__close">×</button>
  </div>
</div>

Drawer Modals

Sidebar Drawer Modals
<!-- Left Drawer -->
<div class="aiab-modal aiab-modal--drawer-left">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__header">
      <h2 class="aiab-modal__title">Navigation</h2>
      <button class="aiab-modal__close">×</button>
    </div>
    <div class="aiab-modal__body">
      <nav>
        <ul>
          <li><a href="#">Home</a></li>
          <li><a href="#">About</a></li>
          <li><a href="#">Services</a></li>
          <li><a href="#">Contact</a></li>
        </ul>
      </nav>
    </div>
  </div>
</div>

<!-- Right Drawer -->
<div class="aiab-modal aiab-modal--drawer-right">...</div>

Bottom Sheet Modal

Mobile-style Bottom Sheet
<div class="aiab-modal aiab-modal--bottom-sheet">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__header">
      <h2 class="aiab-modal__title">Actions</h2>
      <button class="aiab-modal__close">×</button>
    </div>
    <div class="aiab-modal__body">
      <div class="list-group">
        <button class="list-group-item">Share</button>
        <button class="list-group-item">Edit</button>
        <button class="list-group-item">Delete</button>
      </div>
    </div>
  </div>
</div>

Modal Animations

Different Animation Styles
<!-- Fade In Animation -->
<div class="aiab-modal aiab-modal--fade-in">...</div>

<!-- Slide Down Animation -->
<div class="aiab-modal aiab-modal--slide-down">...</div>

<!-- Zoom In Animation -->
<div class="aiab-modal aiab-modal--zoom-in">...</div>

Loading State

Modal with Loading Spinner
<div class="aiab-modal aiab-modal--loading">
  <div class="aiab-modal__dialog">
    <div class="aiab-modal__header">
      <h2 class="aiab-modal__title">Loading...</h2>
    </div>
    <div class="aiab-modal__body">
      <div class="aiab-modal__spinner"></div>
    </div>
  </div>
</div>

CSS Classes Reference

Base Classes

Class Description
.aiab-modal Base aiab-modal aiab-container
.aiab-modal-backdrop Modal backdrop overlay
.aiab-modal__dialog Modal dialog box
.aiab-modal__header Modal header section
.aiab-modal__title Modal title
.aiab-modal__close Close button
.aiab-modal__body Modal content area
.aiab-modal__footer Modal footer section

Size Modifiers

Class Description Max Width
.aiab-modal--sm Small aiab-modal 300px
Default Default aiab-modal 500px
.aiab-modal--lg Large aiab-modal 800px
.aiab-modal--xl Extra large aiab-modal 1140px
.aiab-modal--full Full screen aiab-modal 95vw

Variant Modifiers

Class Description
.aiab-modal--alert Alert style aiab-modal
.aiab-modal--image Image lightbox aiab-modal
.aiab-modal--drawer-left Left aiab-sidebar drawer
.aiab-modal--drawer-right Right aiab-sidebar drawer
.aiab-modal--bottom-sheet Bottom sheet aiab-modal
.aiab-modal--loading Loading state aiab-modal

Animation Modifiers

Class Description
.aiab-modal--fade-in Fade in animation
.aiab-modal--slide-down Slide down animation
.aiab-modal--zoom-in Zoom in animation

State Classes

Class Description
.aiab-is-visible Shows the aiab-modal
.aiab-modal-open Applied to body to prevent scrolling

JavaScript Integration

// Modal management utility
class Modal {
  constructor(element) {
    this.modal = element;
    this.backdrop = document.querySelector('.aiab-modal-backdrop');
    this.isVisible = false;
    this.init();
  }

  init() {
    // Close button
    const closeBtn = this.modal.querySelector('.aiab-modal__close');
    if (closeBtn) {
      closeBtn.addEventListener('click', () => this.hide());
    }

    // Backdrop click
    if (this.backdrop) {
      this.backdrop.addEventListener('click', () => this.hide());
    }

    // Escape key
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && this.isVisible) {
        this.hide();
      }
    });
  }

  show() {
    this.isVisible = true;
    document.body.classList.add('aiab-modal-open');

    if (this.backdrop) {
      this.backdrop.classList.add('aiab-is-visible');
    }

    this.modal.classList.add('aiab-is-visible');
    this.modal.setAttribute('aria-hidden', 'false');

    // Focus management
    this.modal.focus();
    this.trapFocus();
  }

  hide() {
    this.isVisible = false;
    document.body.classList.remove('aiab-modal-open');

    if (this.backdrop) {
      this.backdrop.classList.remove('aiab-is-visible');
    }

    this.modal.classList.remove('aiab-is-visible');
    this.modal.setAttribute('aria-hidden', 'true');
  }

  trapFocus() {
    const focusableElements = this.modal.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );

    if (focusableElements.length === 0) return;

    const firstElement = focusableElements[0];
    const lastElement = focusableElements[focusableElements.length - 1];

    this.modal.addEventListener('keydown', (e) => {
      if (e.key === 'Tab') {
        if (e.shiftKey) {
          if (document.activeElement === firstElement) {
            lastElement.focus();
            e.preventDefault();
          }
        } else {
          if (document.activeElement === lastElement) {
            firstElement.focus();
            e.preventDefault();
          }
        }
      }
    });
  }
}

// Usage
const modal = new Modal(document.getElementById('my-modal'));
modal.show(); // Open aiab-modal
modal.hide(); // Close aiab-modal

// Quick show function
function showModal(modalId) {
  const modal = new Modal(document.getElementById(modalId));
  modal.show();
}

Best Practices

Accessibility Guidelines

UX Considerations

Performance Tips