JavaScript Modals Recipe

Posted on May 20, 2024

by Jimmy

Last updated on February 13, 2025


The simplest way I found to implement modals. This snippet will allow you to add multiple modals onto a page.

HTML
        
            <dialog class="modal" id="modal-1">
    <button class="close-modal">Close</button>
    <div class="modal__content">
        Modal #1 content goes here.
    </div>
</dialog>

<dialog class="modal" id="modal-2">
    <button class="close-modal">Close</button>
    <div class="modal__content">
        Modal #2 content goes here.
    </div>
</dialog>
        
<button class="open-modal" data-target="#modal-1">Open Modal 1</button>
<button class="open-modal" data-target="#modal-2">Open Modal 2</button>        
    

Note

The octothorpe (# symbol) in the data-target value is required for this to work.

CSS
        
            .modal {
  display: block; /** <-- Required to make the animation work */
  max-width: 1400px;
  width: 90%;
  opacity: 0;
  transform: translateY(15%);
  transition: transform 0.4s ease, opacity 0.2s ease;
  border: none;
  visibility: hidden;
  overflow: visible;
}

.modal::backdrop {
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
}

.modal[open] {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.close-modal {
  position: absolute;
  top: 10px;
  right: 10px;
  cursor: pointer;
}        
    
JavaScript
        
            const initModals = () => {
  // Guard: if no modal on page
  if(!document.querySelector(".modal")) return;

  const modals = document.querySelectorAll('.modal');
  const openButtons =  document.querySelectorAll('[data-target]');
  const closeButtons = document.querySelectorAll('.close-modal');

  // Open modal
  openButtons.forEach((button) => {
    button.addEventListener('click', (e) => {
      e.preventDefault();
      const modal = document.querySelector(button.dataset.target);
      modal.showModal();
    });
  });

  // Close modal
  closeButtons.forEach((button) => {
    button.addEventListener('click', () => {
      const modal = button.closest('.modal');
      modal.close();
    });
  });

  // Close on outside click
  modals.forEach((modal) => {
    modal.addEventListener("click", e => {
      const dialogDimensions = modal.getBoundingClientRect()
      if (
        e.clientX < dialogDimensions.left ||
        e.clientX > dialogDimensions.right ||
        e.clientY < dialogDimensions.top ||
        e.clientY > dialogDimensions.bottom
      ) {
        modal.close()
      }
    })
  });
}        
    

Run the function after the page is done loading:

JavaScript
        
            window.addEventListener("DOMContentLoaded", () => {
    initModals();
});        
    

Optional: Stop video on modal close

If you have a video in your modal and need it to stop playing when the modal is closed, use this function:

JavaScript
        
            const stopVideo = ( element ) => {
    let iframe = element.querySelector( 'iframe');
    let video = element.querySelector( 'video' );
    if ( iframe ) {
      let iframeSrc = iframe.src;
      iframe.src = iframeSrc;
    }
    if ( video ) {
      video.pause();
    }
};        
    

Complete JavaScript code with function to stop videos on close:

JavaScript
        
            const initModals = () => {
  // Guard: if no modal on page
  if(!document.querySelector(".modal")) return;

  const modals = document.querySelectorAll('.modal');
  const openButtons =  document.querySelectorAll('[data-target]');
  const closeButtons = document.querySelectorAll('.close-modal');

  // Open modal
  openButtons.forEach((button) => {
    button.addEventListener('click', (e) => {
      e.preventDefault();
      const modal = document.querySelector(button.dataset.target);
      modal.showModal();
    });
  });

  // Close modal
  closeButtons.forEach((button) => {
    button.addEventListener('click', () => {
      const modal = button.closest('.modal');
      modal.close();
      stopVideo(modal);
    });
  });

  // Close on outside click
  modals.forEach((modal) => {
    modal.addEventListener("click", e => {
      const dialogDimensions = modal.getBoundingClientRect()

      if (
        e.clientX < dialogDimensions.left ||
        e.clientX > dialogDimensions.right ||
        e.clientY < dialogDimensions.top ||
        e.clientY > dialogDimensions.bottom
      ) {
        modal.close()
        stopVideo(modal);
      }
    })
  });

  // Stop video when modal is closed (optional - remove if videos will ever exist in the modal)
  const stopVideo = ( element ) => {
    let iframe = element.querySelector( 'iframe');
    let video = element.querySelector( 'video' );
    if ( iframe ) {
      let iframeSrc = iframe.src;
      iframe.src = iframeSrc;
    }
    if ( video ) {
      video.pause();
    }
  };
}        
    

Back to Snippets