6

How would you close dialog box by clicking outside of it in addition to clicking the Esc button?

<!DOCTYPE html>
<html>
<body>

<p>Click the button to show the dialog.</p>

<button onclick="myFunction()">Show dialog</button>

<p><b>Note:</b> Use the "Esc" button to close the modal.</p>
<p><b>Note:</b> The dialog element is only supported in Chrome 37+, Safari 6+ and Opera 24+.</p>

<dialog id="myDialog">This is a dialog window</dialog>

<script>
function myFunction() { 
  document.getElementById("myDialog").showModal(); 
} 
</script>

</body>
</html>

CC BY-SA 4.0
4

5 Answers 5

6

The showModal() method of the HTMLDialogElement interface displays the dialog as a modal, over the top of any other dialogs that might be present. It displays into the top layer, along with a ::backdrop pseudo-element. Interaction outside the dialog is blocked and the content outside it is rendered inert. MDN documentation

As you can see, outside of the dialog all other html nodes will be blocked. But, we can add a child node as a wrapper for our content, thus we separate our content from the outside area. Let's remove the extra padding from dialog with css and add it to the modal class.

const dialog = document.getElementById('myDialog');
const button = document.querySelector('button');

function openDialog() {
  dialog.showModal();
}

function closeDialog(event) {
  // If the target dialog is
  if (!event.target.contains(dialog)) return;
  dialog.close();
}

button.addEventListener('click', openDialog);
document.addEventListener('click', closeDialog);
dialog {
  padding: 0;
}

.modal {
  display: flex;
  padding: 1rem;
}

dialog::backdrop {
  background-color: rgba(255, 0, 0, 0.25);
}
<p>Click the button to show the dialog.</p>

<button>Show dialog</button>

<p><b>Note:</b> Use the "Esc" button to close the modal.</p>
<p><b>Note:</b> The dialog element is only supported in Chrome 37+, Safari 6+ and Opera 24+.</p>

<dialog id="myDialog">
  <div class="modal">
    <p>This is a dialog window</p>
  </div>
</dialog>

CC BY-SA 4.0
4

You can also try the way described by Adam Argyle here: https://web.dev/building-a-dialog-component/#adding-light-dismiss

  1. Get the dialog element and add an event listener to the dialog element
    const dialog = document.querySelector('dialog);

    dialog.addEventListener('click', lightDismiss);
  1. Create the handler function and check whether the dialog element triggered the event. If yes, call .close() method. This works because, by default, the dialog element creates a backdrop that covers all other elements on the page, and clicking there === clicking on the dialog element itself. This will not affect children elements inside the dialog, so clicking there will not close the dialog.
    const lightDismiss = ({target:dialog}) => {
      if (dialog.nodeName === 'DIALOG')
        dialog.close('dismiss')
    }

By the way, I recommend reading this wonderful dialog tutorial.

CC BY-SA 4.0
1
0

In general, you can use the onblur- or onfocusout-event. Both fire when you leave the element aka. click on another element. (Though I haven't tested it with a dialog specifically.)

<dialog onblur="yourFunction()">
CC BY-SA 4.0
1
0

I know it is a little bit impractical but you can add a div that is as big as the whole screen and, when you click on 'show dialog', the div's display is block and when you click on the div that has the size of the screen, the dialog disappears.

<!DOCTYPE html>
<html>
<body>

<p>Click the button to show the dialog.</p>

<button onclick="myFunction()">Show dialog</button>

<p><b>Note:</b> Use the "Esc" button to close the modal.</p>
<p><b>Note:</b> The dialog element is only supported in Chrome 37+, Safari 6+ and Opera 24+.</p>

<div id="close-dialog-element" onclick="closeDialog()">
    <dialog close id="myDialog">This is a dialog window</dialog>
</div>

<style>
#close-dialog-window {
    width: 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
}

#myDialog {
    z-index: 11;
}
</style>

<script>
function closeDialog() {
    document.getElementById('close-dialog-element').style.display = 'none';
    document.getElementById('myDialog').close();
}

function myFunction() { 
  document.getElementById("myDialog").showModal(); 
} 
</script>

</body>
</html>

CC BY-SA 4.0
-1

.showModal() uses a ::backdrop which is a pseudo-element which is invisible to the DOM, therefore untouchable. The example below shows how to use the .show() method so that a click outside a <dialog> is possible.

Details are commented in example

// Reference <dialog> and <button>
const modal = document.querySelector('.modal');
const open = document.querySelector('.open');

// Bind click event to <button>
open.onclick = openModal;
// Bind click event to <main>
document.querySelector('main').onclick = closeModal;
// Bind keydown event close the <dialog> when Esc key is clicked
document.onkeydown = e => {
  if (e.key === "Escape") {
    closeModal(e);
  }
}

function openModal(e) {
  // This opens <dialog> with no ::backdrop
  modal.show();
  // A .open to <html> so it appears there's a ::backdrop
  document.documentElement.classList.add('open');
  // Disable <button>
  this.disabled = true;
}

function closeModal(e) {
  // Reference the tag the user clicked
  const clk = e.target;
  /*
  If the user clicked the <dialog> or anything within the
  <dialog> OR the <button>...
  ... do nothing...
  ... otherwise close <dialog>...
  ... remove .open from <html>...
  ... enable <button>
  */
  if (modal.contains(clk) || clk.matches('.open')) {
    return
  }
  modal.close();
  document.documentElement.classList.remove('open');
  open.disabled = false;
}
/* Simulate a ::backdrop */
:root.open {
  overflow: hidden;
  background-color: rgba(0, 0, 0, 0.2);
}

/* Cover all of viewport */
main {
  width: 100%;
  min-height: 100vh;
}

/* When <dialog> is open <button> should be inert */
.open .open {
  pointer-events: none;
}
<!DOCTYPE html>
<html>

<body>
  <!-- Wrap everything with <main> -->
  <main>
    <p>Click the button to show the dialog.</p>

    <button class='open'>Show Modal</button>

    <dialog class="modal">
      <p><b>Note:</b> Use the "Esc" button to close the modal.</p>
      <p><b>Note:</b> Or click outside of modal to close it.</p>
    </dialog>

  </main>
</body>

</html>

CC BY-SA 4.0

Not the answer you're looking for? Browse other questions tagged or ask your own question.