mending3
mending3

Reputation: 712

Close custom modal when click outside the modal in vanilla JS

I've done this but the modal won't open whatsoever

document.addEventListener('click', ({ target }) => {
            if (!target.closest('#modal-submit')) {
               document.getElementById('modal-submit').classList.add('hide-visibility');
            }
        })

The trickier part is that there's a form inside the modal.

This to trick "mostly code" error: ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

document.getElementById('show-modal').onclick = (e) => {
  document.getElementById('modal-submit').classList.remove('hide-visibility')
}
.hide-visibility {
            opacity: 0;
            visibility: hidden;
        }
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css" rel="stylesheet"/>

<div
        id="modal-submit"
        class="fixed z-10 inset-0 overflow-y-auto hide-visibility"
        style="z-index: 9999; transition: all .5s;"
        aria-labelledby="modal-title"
        role="dialog"
        aria-modal="true"
    >
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
            <!--
              Background overlay, show/hide based on modal state.

              Entering: "ease-out duration-300"
                From: "opacity-0"
                To: "opacity-100"
              Leaving: "ease-in duration-200"
                From: "opacity-100"
                To: "opacity-0"
            -->
            <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>

            <!-- This element is to trick the browser into centering the modal contents. -->
            <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>

            <!--
              Modal panel, show/hide based on modal state.

              Entering: "ease-out duration-300"
                From: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
                To: "opacity-100 translate-y-0 sm:scale-100"
              Leaving: "ease-in duration-200"
                From: "opacity-100 translate-y-0 sm:scale-100"
                To: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
            -->
            <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
                <div class="bg-white px-4 pb-4 sm:p-3 sm:pb-4">
                    <h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
                        Submit Exam
                    </h3>
                    <div class="mt-5">
                        <p class="text-sm text-gray-500">
                            <input id="certify-checkbox" type="checkbox" class="form-checkbox h-3 w-3 text-gray-600">
                            I certify that 
                        </p>
                    </div>
                    <div class="mt-5">
                        <p class="text-sm text-gray-500">
                            <input id="final-checkbox" type="checkbox" class="form-checkbox h-3 w-3 text-gray-600">
                            I have conducted a final round of proofing before submitting this project.
                        </p>
                    </div>
                </div>
                <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                    <button type="button" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm">
                        Submit
                    </button>
                </div>
            </div>
        </div>
    </div>
    
<button id="show-modal" class="border border-indigo-600">Show</button>

Upvotes: 0

Views: 1535

Answers (1)

Nikhil Singh
Nikhil Singh

Reputation: 1610

document.getElementById("show-modal").onclick = (e) => {
  document.getElementById("modal-submit").classList.remove("hide-visibility");
};

document.addEventListener('click', (event) => {
  const boolIsOutside = document.getElementById("grey-bg").isSameNode(event.target);
  if (boolIsOutside) {
   document.getElementById("modal-submit").classList.add("hide-visibility");
  }
});
.hide-visibility {
            opacity: 0;
            visibility: hidden;
        }
<div
        id="modal-submit"
        class="fixed z-10 inset-0 overflow-y-auto hide-visibility"
        style="z-index: 9999; transition: all .5s; border: 2px solid black"
        aria-labelledby="modal-title"
        role="dialog"
        aria-modal="true"
    >
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
            <!--
              Background overlay, show/hide based on modal state.

              Entering: "ease-out duration-300"
                From: "opacity-0"
                To: "opacity-100"
              Leaving: "ease-in duration-200"
                From: "opacity-100"
                To: "opacity-0"
            -->
            <div id="grey-bg" class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>

            <!-- This element is to trick the browser into centering the modal contents. -->
            <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>

            <!--
              Modal panel, show/hide based on modal state.

              Entering: "ease-out duration-300"
                From: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
                To: "opacity-100 translate-y-0 sm:scale-100"
              Leaving: "ease-in duration-200"
                From: "opacity-100 translate-y-0 sm:scale-100"
                To: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
            -->
            <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
                <div class="bg-white px-4 pb-4 sm:p-3 sm:pb-4">
                    <h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
                        Submit Exam
                    </h3>
                    <div class="mt-5">
                        <p class="text-sm text-gray-500">
                            <input id="certify-checkbox" type="checkbox" class="form-checkbox h-3 w-3 text-gray-600">
                            I certify that 
                        </p>
                    </div>
                    <div class="mt-5">
                        <p class="text-sm text-gray-500">
                            <input id="final-checkbox" type="checkbox" class="form-checkbox h-3 w-3 text-gray-600">
                            I have conducted a final round of proofing before submitting this project.
                        </p>
                    </div>
                </div>
                <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                    <button type="button" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm">
                        Submit
                    </button>
                </div>
            </div>
        </div>
    </div>
    
<button id="show-modal" class="border border-indigo-600">Show</button>

Using the concept of event propagation, you can use this,

// You can use any other selector according to your need
const ele = document.getElementById('someId');

// adding click event listener to the selected elem (can use any other event)
document.addEventListener('click', (event) => {
  const boolIsInside = ele.contains(event.target);
  if (boolIsInside) {
    // logic if the click was inside the modal
  } else {
    // logic if the click was outside the modal
  }
});

Upvotes: 1

Related Questions