12

Using the material design lite library to create dialogs, which essentially uses the underlying <dialog> element, is there any way to dismiss the dialog by clicking on its backdrop? (When clicking the dialog contents themselves it should not be dismissed).

<dialog>Hi</dialog>    
<button>show</button>

document.querySelector("button").addEventListener("click",
  () => document.querySelector("dialog").showModal());

https://jsfiddle.net/fyjbvbqq/

Clicking anywhere on the screen when the dialog is shown corresponds to clicking the dialog element so it seems like there is no simple way to determine if the backdrop was clicked ... is there a way to do this?

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405

2 Answers2

3

You might use the Element.getBoundingClientRect to get size and position of the dialog and test if the current client coordinates are inside this area:

document.querySelector("button").addEventListener("click", () => document.querySelector("dialog").showModal());
document.querySelector("dialog").addEventListener("click", (e) => {
  var rect = e.target.getBoundingClientRect();
  var minX = rect.left + e.target.clientLeft;
  var minY = rect.top + e.target.clientTop;
  if ((e.clientX < minX || e.clientX >= minX + e.target.clientWidth) ||
      (e.clientY < minY || e.clientY >= minY + e.target.clientHeight)) {
    e.target.close();
  }
});
<dialog>Hi</dialog>

<button>
    show
</button>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
  • This is pretty close, but I think I want the opposite of this logic (clicking the backdrop dismisses; when I run your snippet I have to click the dialog itself to dismiss it) – Explosion Pills Oct 13 '16 at 19:14
  • @ExplosionPills Fixed. Sorry for my english, I understood exactly the opposite. Now, only clicking outside, the dialog will be dissmissed. – gaetanoM Oct 13 '16 at 19:35
  • Thanks! the only issue I see is that the bounding box border can also be clicked to dismiss the modal, but this isn't a big deal. Just wondering if there is an easy way to handle that – Explosion Pills Oct 13 '16 at 20:12
2

A current succinct way of handling this problem is:

dialog.addEventListener('click', ({target:dialog}) => {
    if (dialog.nodeName === 'DIALOG') {
        dialog.close('dismiss');
    }
});

This works because clicks inside the dialog itself will have the nodeName of the dialog content (e.g. P, FORM, etc.), whereas clicks on the backdrop will have the nodeName of DIALOG.

Source: "Adding Light Dismiss" on web.dev

Pete
  • 7,289
  • 10
  • 39
  • 63