What is the best way to trigger multiple modalboxes using JavaScript?

I am facing an issue with a modal box on my webpage. The first modal opens correctly when clicking a button, but after duplicating it for a second modal, the second one fails to open upon clicking the button.

Is there a way to trigger the second modal using the same classes and JavaScript function without adding additional code? Or can the second modal be activated with minimal code?

/* Modal Box Js */
const modal = document.querySelector(".modal");
const trigger = document.querySelector(".trigger");
const closeButton = document.querySelector(".close-button");

function toggleModal() {
    modal.classList.toggle("show-modal");
}

function windowOnClick(event) {
    if (event.target === modal) {
        toggleModal();
    }
}

trigger.addEventListener("click", toggleModal);
closeButton.addEventListener("click", toggleModal);
window.addEventListener("click", windowOnClick);
/**********
Modal Box Style
**********/
.trigger {cursor: pointer;}

.modal {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  opacity: 0;
  visibility: hidden;
  transform: scale(1.1);
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
}

.modal-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: white;
  padding: 20px;
  width: 40rem;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
}

.msg-title {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 12px;
}

.msg-text {
  font-size: 14px;
  margin-bottom: 6px;
  color: #5B616D;
}

.close-button {
  float: right;
  width: 1.5rem;
  line-height: 1.5rem;
  text-align: center;
  cursor: pointer;
  border-radius: 0.25rem;
  background-color: lightgray;
  align-self: end;
}

.close-button:hover {
  background-color: darkgray;
}

.show-modal {
  opacity: 1;
  visibility: visible;
  transform: scale(1.0);
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
<!-- Modal Box 1 -->
<div class="trigger">Modal Box 1</div>
<div class="modal">
  <div class="modal-content">
    <span class="close-button">×</span>
    <span class="msg-title">Title 1</span>
    <span class="msg-text">
      “If you are distressed by anything external, the pain is not due to the thing itself, but to your estimate of it;       and this you have the power to revoke at any moment.”
      ― Marcus Aurelius.
    </span>
  </div>
</div>


<!-- Modal Box 2 -->
<div class="trigger">Modal Box 2</div>
<div class="modal">
  <div class="modal-content">
    <span class="close-button">×</span>
    <span class="msg-title">Title 2</span>
    <span class="msg-text">
      “If you are distressed by anything external, the pain is not due to the thing itself, but to your estimate of it;       and this you have the power to revoke at any moment.”
      ― Marcus Aurelius.
    </span>
  </div>
</div>

Answer №1

Your primary issue stemmed from the lack of utilizing NodeList.forEach to both assign clicks to the desired elements and for neglecting to loop through the modals to toggle the "open" class.

Here's an alternative version of your code that incorporates the aforementioned method along with a more suitable tool, data-* attribute, specifically data-modal, which allows you to reference the desired modal to toggle without being restricted by a fixed HTML structure or limited to one button element per modal.

An additional problem addressed is the avoidance of negative transforms in CSS for centering modal content. Instead, it suggests using margin: auto within a flex parent and including scrollbars as necessary (refer to the comments in the CSS).

// Helper functions:

const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);

// Task: Modal Box

const elsModals = els(".modal");
const elsModalBtns = els("[data-modal]");

const modalToggle = (id) => {
  el(id).classList.toggle("show-modal");
};

const modalsClose = (evt) => {
  // No action if click occurred inside a modal or modal button:
  if (evt.target.closest(".modal-content") || evt.target.closest("[data-modal]")) return;
  // Otherwise, close all modals:
  elsModals.forEach(elMod => elMod.classList.remove("show-modal"));
}

elsModalBtns.forEach(elBtn => {
  elBtn.addEventListener("click", () => modalToggle(elBtn.dataset.modal));
});

addEventListener("click", modalsClose);
/*
 * Modal Box
 */

.trigger {
  cursor: pointer;
}

.modal {
  position: fixed;
  display: flex;
  /* Use flex!!! */
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  opacity: 0;
  visibility: hidden;
  transform: scale(1.1);
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
}

.modal-content {
  margin: auto; /* Center inside flex parent */
  overflow: auto; /* Scroll inner content if needed */
  max-height: 70vh; /* Enable scrolling if exceeds this height */
  background-color: white;
  padding: 20px;
  width: 40rem;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
}

.msg-title {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 12px;
}

.msg-text {
  font-size: 14px;
  margin-bottom: 6px;
  color: #5B616D;
}

.close-button {
  text-align: center;
  cursor: pointer;
  border-radius: 0.25rem;
  background-color: lightgray;
  align-self: end;
  border: 0;
  font-size: 1.2rem;
}

.close-button:hover {
  background-color: darkgray;
}

.show-modal {
  opacity: 1;
  visibility: visible;
  transform: scale(1.0);
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
<div class="trigger" data-modal="#modal-lorem">Modal Box 1</div>
<div class="trigger" data-modal="#modal-aurelius">Modal Box 2</div>

<div id="modal-lorem" class="modal">
  <div class="modal-content">
    <button type="button" class="close-button" data-modal="#modal-lorem">×</button>
    <span class="msg-title">Title 1</span>
    <span class="msg-text">
      “Dolor sit amet, consectetur adipisicing elit. Numquam earum debitis architecto, temporibus quod maxime velit, rem ex nam eum ea illum, assumenda nesciunt consectetur quaerat. Accusamus reprehenderit, distinctio et!
”
      ― Lorem ipsum.
    </span>
  </div>
</div>


<div id="modal-aurelius" class="modal">
  <div class="modal-content">
    <button type="button" class="close-button" data-modal="#modal-aurelius">×</button>
    <span class="msg-title">Title 2</span>
    <span class="msg-text">
      “he pain is not due to the thing itself, but to your estimate of it;       and this you have the power to revoke at any moment.”
      ― Marcus Aurelius.
    </span>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

what is the process for installing non-NPM libraries with browserify?

My current project involves working with Angular and using Bower as the package manager. However, I now want to integrate some npm modules in the browser by using Browserify. Initially, I was able to npm install angular angular-ui-router --save for my sta ...

Creating Dynamic UI in React Native by Displaying POST Request Data on Screen

Here's a scenario where I have set up a post route: router.post("/projects", async (req, res) => { const { projectName, projectDescription, projectBudget, projectDuration, industry, companyName, numberOfEmployees, ...

Trouble encountered when implementing setInterval in Next.js

While working on a progress bar component in Next.js and tailwind.css, I used JavaScript's setInterval() function for animation. Below is the code snippet: import React, { useState } from "react"; const ProgressBar = () => { let [progress, setPr ...

How do I set up a timing mechanism in a VSCode extension to automatically clear error messages after a specified duration?

I'm currently in the process of developing a VSCode extension, and ran into an issue where I need to display an error message if a certain condition is met. However, I want this error message to automatically disappear after a set amount of time (say, ...

Upgrading Pagination from Bootstrap 3 to Bootstrap 4: A Step-by-

I am currently transferring an application from Bootstrap 3 where the previous pager had this appearance: https://i.sstatic.net/0gqIo.png Here is the code snippet for the old pager: <nav> <ul class="pager"> <li class="previous ...

React Native formInput Component with Underline Decoration

Utilizing the FormInput element in React Native Elements, I have observed a line underneath each FormInput component. Interestingly, one line appears fainter than the other. https://i.sstatic.net/ZD8CI.png This is how the form looks: <View style={sty ...

The pre-set value in the search bar of the Google specialized search

Is it possible to pre-fill the search field with text when the Google Custom Search page is loaded using the standard copy and paste code (free with ads)? If yes, how can this be achieved? Below is the code snippet: <div id="cse" style="width: 100%;" ...

I am looking to create a route with parameters in Next.js, as well as without any parameters

I am working on a NEXTJS project and utilizing SSR for data fetching. However, I am trying to implement the following scenario: When users land on the "/" route, they should be presented with a random product detail page. But if they search for a specific ...

What is the best way to perfectly match a blurry background image within a card?

Hi there, I am new to CSS and trying to create a card with a blurred background. However, I have encountered an issue where the blurred image overflows on the border of the card. I tried using -webkit-filter: blur(8px) in a separate div for the image but ...

Vanishing elements when employing the react-router library in a React project

Currently, I am in the process of developing a React application and have encountered an issue with components disappearing upon refresh. It seems to be related to React Router, suggesting that I may be implementing it incorrectly. This is what my App.js ...

What is the best way to assign classes to the appropriate element based on the counter value?

Is there a way to add a class to the element that corresponds to a counter in jQuery? I currently have this code: var li_counter = 0; $("#trigger_heritage").click(function () { if(heritage_position >= heritage_versatz*13){ li_co ...

swap out a single amchart for a different one

Here's the current amchart I have: https://i.sstatic.net/J8QLl.png I'm looking to create another amchart with the same data. Essentially, I want to replace the existing graph. You can find the new chart here -> This is my Angular code: pre ...

Embedding version 8: navigating a basic class

After following the example in the V8 embedder's guide for "Accessing Dynamic Variables," I have successfully adjusted the code to compile with the newest version. However, the example only demonstrates how to define accessors for a Class. If I want t ...

How can you receive a file through AJAX response?

I have a standard Ajax function that I regularly use to call a specific function within my node.js server. This particular function is responsible for retrieving a file (usually in xls format) from the server and streaming it back to the client. Below is ...

"Utilize Vue i18n to properly display currency amounts in USD

Whenever I present my currency as USD, it always shows up like this: USD$500.00. I am attempting to eliminate the USD prefix from the beginning. Below is my numberFormats configuration: numberFormats: { 'en': { currency: { ...

Encountered a problem when injecting the angularjs $location service

I'm having some trouble getting the $location service to work in this code snippet: <script type="text/javascript> var $injector = angular.injector(['ng', 'kinvey', 'app.constants']); $in ...

Is there a way to get rid of the "bouncing effect" on my button while using an inline floating-label text input?

When an input with a floating label (Bootstrap 5) is inline with other elements, the elements may appear to jump up and down depending on the position of the floating label. https://i.sstatic.net/kDxBo.gif <link href="https://cdn.jsdelivr.net/npm/bo ...

Send the form's ID as an argument to the click() function

I am dealing with 24 buttons that look like this: `<form id="start_0" class="KEY_MENU"> <button class="btnn">1</button> </form> <form id="start" class="KEY_OK"> <button clas ...

Struggling to correct alignment issues with buttons within a container using Bootstrap 5

I'm struggling with a piece of html code where everything looks good except for the placement of the button. It seems to be too far away from the container. Here's the code snippet: <div class="container-fluid mt-1 d-flex align-items-cent ...

"The issue with AngularJS ng-init, preventing the initialization of a variable at

For my project, I have implemented ng-repeat from the AngularJS directive to display an array containing JSON values with subarrays. <div ng-repeat="data in MENULIST" > //MENULIST contains an array of data I then perform certain conditions checks ...