DEV Community

Cover image for Vanilla JavaScript - Modal
serhatbek
serhatbek

Posted on • Edited on

Vanilla JavaScript - Modal

In this article, we'll build a modal using vanilla JavaScript, HTML, and SCSS that will include features like opening and closing with a button, and closing when clicking outside of the modal content.

Before we start I'd like mention that I used:

Modal HTML Structure

The HTML structure of the modal includes a button to trigger the modal and the modal itself with an overlay and content area.

<!-- Add Boxicons to html head tag -->
<link
  href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css"
  rel="stylesheet"
/>

<body class="container">
  <button class="btn js-show-modal">
    Show Modal
    <i class="bx bx-right-arrow-alt"></i>
  </button>

  <div class="modal js-modal">
    <div class="modal__overlay"></div>
    <div class="modal__content">
      <button class="modal__close js-close-modal">
        <i class="bx bx-x-circle"></i>
      </button>

      <h4>Lorem ipsum dolor sit amet consectetur adipisicing!</h4>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Explicabo hic
        earum possimus itaque, aperiam tenetur quo ducimus doloremque maxime
        voluptas natus laudantium nemo maiores ex ipsam quis. Nobis atque
        incidunt esse architecto cupiditate quis neque ipsa animi deserunt
        commodi perspiciatis aperiam nemo dignissimos libero, fugit dolorum
        similique quas, ducimus ad?
      </p>
      <div class="modal__action">
        <button class="btn js-close-modal">Close</button>
      </div>
    </div>
  </div>
</body>
Enter fullscreen mode Exit fullscreen mode

SCSS Styling

The SCSS for the modal ensures it is visually appealing and functions correctly when opened and closed.

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');

// COLORS
// $black: #202b2f;
$black2: #1e1e1e;
$white: aliceblue;
$grayish-blue: #003249;
$blue: #4983cf;
$pink: #be5064;

// RESET
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Roboto', sans-serif;
  background-color: $grayish-blue;
  color: $white;

  &.overflowHidden {
    overflow: hidden;
  }
}

// STYLES
.container {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn {
  font-size: 14px;
  color: $white;
  padding: 8px 16px;
  background-color: $blue;
  border: 0;
  cursor: pointer;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;

  > i {
    font-size: 18px;
  }
}

.modal {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  opacity: 0;
  user-select: none;
  pointer-events: none;
  z-index: -22;
  transition: all 200ms ease-in-out;

  &--opened {
    opacity: 1;
    user-select: auto;
    pointer-events: all;
    z-index: 1;
  }

  &__overlay {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: rgba($color: $black2, $alpha: 0.8);
    z-index: 11;
  }

  &__close {
    border: 0;
    outline: 0;
    background-color: transparent;
    font-size: 24px;
    position: absolute;
    right: 20px;
    top: 20px;
    cursor: pointer;

    > i {
      font-size: 34px;
      color: $pink;
    }
  }

  &__content {
    background-color: $white;
    color: $black2;
    max-width: 600px;
    width: 100%;
    padding: 30px;
    border-radius: 8px;
    z-index: 22;
    position: relative;

    > h4 {
      font-size: 18px;
      margin: 30px 0;
    }

    > p {
      margin-bottom: 20px;
    }
  }

  &__action {
    text-align: right;
  }
}
Enter fullscreen mode Exit fullscreen mode

Adding JavaScript Functionality

The JavaScript code handles the opening and closing of the modal, including the feature to close the modal when clicking outside of it. We add an event listener to the button with the class js-show-modal. When this button is clicked, the modal--opened class is added to the modal, making it visible.Then we add event listeners to all elements with the class js-close-modal. When any of these elements are clicked, the modal--opened class is removed, hiding the modal. Lastly, We add an event listener to the document. If the modal is open and the user clicks outside the modal content (but not on the trigger button), the modal will close.

document.addEventListener('DOMContentLoaded', () => {
  const modal = document.querySelector('.js-modal'),
    openModalBtn = document.querySelector('.js-show-modal'),
    closeModalBtns = document.querySelectorAll('.js-close-modal'),
    body = document.querySelector('body');

  const closeModal = () => {
    modal.classList.remove('modal--opened');
    body.classList.remove('overflowHidden');
    document.removeEventListener('keydown', handleEscClose);
  };

  const openModal = () => {
    modal.classList.add('modal--opened');
    body.classList.add('overflowHidden');
    document.addEventListener('keydown', handleEscClose);
  };

  const handleEscClose = (e) => {
    if (e.key === 'Escape') {
      closeModal();
    }
  };

  if (modal) {
    openModalBtn.addEventListener('click', openModal);
    closeModalBtns.forEach((btn) => btn.addEventListener('click', closeModal));
  }

  document.addEventListener('click', (event) => {
    if (
      modal.classList.contains('modal--opened') &&
      !event.target.closest('.modal__content') &&
      !event.target.closest('.js-show-modal')
    ) {
      closeModal();
    }
  });
});
Enter fullscreen mode Exit fullscreen mode

We've just created a simple modal component using vanilla JavaScript. You can customize it for your project's needs. To see the detailed code check project's Github repo and Codepen for live demo.

Thank you for reading. If you find the article useful, please do not forget to give a star so that others can access it. Happy Coding! ๐Ÿ™ƒ

Buy Me A Coffee

Top comments (5)

Collapse
 
mobilepadawan profile image
Fer4.9.js • Edited

Hi!
This is a good practice to understand how to converge the different languages to work togheter but since a couple of years ago the Modal things in HTML5 has its proper tag: <dialog>. This HTML tag is so new, I think it has no more than 3 or 4 years old. It was created with the purpose to contribute in the semantic way for a correct SEO indexing of the web browsers among other things.

It is very easy to use, requires just a simple lines of CSS to configure it, and also has two attribute-value or JavaScript methods to control it in open - close processes.

<dialog>
    <h2>Hello</h2>
    <p>Hello world.</p>
    <button>close</button>
</dialog>
Enter fullscreen mode Exit fullscreen mode

This code doesn't show the modal HTML tag. You must add it the boolean attribute open to show it on screen and remove it to close the dialog tag.

From JS you can control it with more precision. First of all, you just link to this tag:

const myModal = document.querySelector('dialog')
Enter fullscreen mode Exit fullscreen mode

And after, when you need to open it, just call the proper method:

myModal.show()
Enter fullscreen mode Exit fullscreen mode

This way to visualize the modal tag, let you close it by pressing the ESC button of your keyboard. But, if you need to show it in a modal way, just call the other method:

myModal.showModal()
Enter fullscreen mode Exit fullscreen mode

This new visualization mode avoid to the user interacts with the back HTML components. You just need a CSS class to apply a backdrop style and make the magic.

When you need to close it, just call myModal.close() and voilร !

Collapse
 
telmopbmarinho profile image
Telmo P. B. Marinho

Very good! I really appreciate this share!

Collapse
 
mobilepadawan profile image
Fer4.9.js

Youโ€™re welcome.
Ask whatever you need if you stucked.

Collapse
 
jonrandy profile image
Jon Randy ๐ŸŽ–๏ธ • Edited

This makes the same mistake as almost every other modal implementation. You can still use the 'tab' key to move to other elements outside of the 'modal', and so can still interact with the page behind the 'modal'. Therefore, it is not truly modal at all.

To implement a modal properly, you either need to jump through a whole bunch of hoops to stop this from happening - or just make use of the built-in dialog HTML element that is designed specifically for this purpose and does not have these issues.

Collapse
 
sourabpramanik profile image
Sourab Pramanik

Things can be as simple as using a dialog tag to build something but using a bunch of listeners and selectors makes it look like something very big is happening and still failing to solve the problem.

Knowing the basics is missing out so much.