Skip to content

Modal

The Modal component provides the base dialog shell used across the site. It handles focus trapping, scroll locking, and cleanup for Astro view transitions, while exposing a small API for external triggers.

  • Type: Utility component
  • Category: Overlays
  • Complexity: Advanced
  • File: src/components/Modal.astro
  • Used by: RegistrationModal, EventHeaderSection
  • Accessible dialog - Proper ARIA attributes and focus handling
  • Focus trap - Keeps Tab navigation inside the modal
  • Scroll lock - Prevents background scrolling (with iOS Safari support)
  • Close handlers - Overlay click, close button, and Escape key
  • Astro-safe cleanup - Removes listeners on astro:before-swap
PropTypeRequiredDefaultDescription
idstring✅ Yes-Unique modal identifier used by triggers
titlestring✅ Yes-Modal heading displayed in the header
maxWidth`‘sm''md''lg''xl'
  1. Import the component in the page or layout:

    ---
    import Modal from '@/components/Modal.astro';
    ---
  2. Render the modal with a unique id and content:

    <Modal id="contact-modal" title="Contact FiNAN" maxWidth="xl">
    <p class="text-gray-700">Hello from the modal body.</p>
    </Modal>
  3. Wire up a trigger by calling the modal API in client-side script:

    <button data-modal-trigger="contact-modal">Open modal</button>
    <script>
    document.addEventListener('astro:page-load', () => {
    const trigger = document.querySelector('[data-modal-trigger="contact-modal"]');
    const modal = document.querySelector('[data-modal="contact-modal"]');
    if (trigger && modal && typeof modal._openModal === 'function') {
    trigger.addEventListener('click', () => modal._openModal(trigger));
    }
    });
    </script>
  • Adds role="dialog", aria-modal="true", and aria-hidden attributes
  • Applies hidden class to toggle visibility
  • Sets a focus ring on the close button for keyboard users
  • Focus returns to the trigger element when the modal closes
  • Escape key always closes the modal
  • Overlay click closes the modal when the overlay element exists
  • Overlay: bg-gray-900/80 for a darkened backdrop
  • Container: rounded-lg bg-white shadow-2xl
  • Header: border-b border-gray-200 with centered heading

View the complete implementation:

https://github.com/poncardasm/finan-website/blob/main/src/components/Modal.astro