Is it possible to position a div on top of a <dialog> tag that is not its parent?
Asked Answered
S

1

19

The <dialog> tag, when opened with showModal(), will display the elements between it and its closing tag while disabling all other elements on the page. My question is: is it possible to override this behavior for a specific element? Example:

HTML:

<div id="container">
  <dialog id="myDialog">
    <button id="close" type="reset">Close</button>
    <button id="create">Add Element</button>
  </dialog>
</div>

<menu>
  <button id="openButton">Open Dialog</button>
</menu>

CSS:

.new-element {
  width: 50px;
  height: 50px;
  border: 3px solid black;
  background-color: blue;
  position: fixed;
  top: 50%;
}

JS:

const container = document.getElementById('container');
const openButton = document.getElementById('openButton');
const closeButton = document.getElementById('close');
const createButton = document.getElementById('create');
const myDialog = document.getElementById('myDialog');

openButton.addEventListener('click', function() {
  myDialog.showModal();
});

closeButton.addEventListener('click', function() {
  myDialog.close();
});

createButton.addEventListener('click', function() {
  const div = document.createElement('div');
  div.classList.add('new-element')
  container.appendChild(div);
});

In a JSFiddle: https://jsfiddle.net/y7bkxvd4/

I'd like to find a way to position the blue square on top of the dialog. I realize it would be far easier to just append the new div to the dialog itself, but I've run into this in a situation where overflow was a concern and in using a module that uses react-portal. If it's not possible, cool, I can get behind that. But if it is, I'd like to know.

z-index has no effect, obviously.

Shawannashawl answered 23/1, 2017 at 20:31 Comment(6)
By "on top of" you mean covering?Teeterboard
@Teeterboard Correct. Covering, in front of, above, etc. Essentially what a higher z-index would do.Shawannashawl
It sounds like you would need another div that would occupy the space where <dialog> currently sits, with positive: relative and the children of it (both the current <dialog> and .new-element) with position: absolute.Flection
How was the overflow a concern in appending straight to dialog?Openhearted
@LGSon Consider this a hypothetical question - I realize it's not ideal in most circumstances, but I couldn't find a definite answer to this question anywhere. I also realize there are other ways to fix overflow issues, but I wanted to know more about the behavior of this particular HTML tag - it might open up other possibilities, or I might find a situation someday where I really am constrained by the actions of a particular module or library.Shawannashawl
Well, in that case the answer is no :), you can't, as it would defeat the purpose of the dialog in the first place.Openhearted
W
24

The <dialog> element is added to the 'Top Layer' of the dom which has its own stacking order (z-index does not affect this -- it is set strictly by the order by which the elements are added). I don't believe you can manually add elements to this Top Layer, it is done in functions such as showModal(). You can find more information at: https://fullscreen.spec.whatwg.org/#new-stacking-layer but because the feature is still not universally supported its tough finding documentation on it. For example:

To remove an element from a top layer, remove element from top layer.

Real helpful..

A couple work arounds:

  • Change the added element to a dialog as well and call .showModal() when the element is appended. The problem with this approach is that .showModal() makes all element outside that element unavailable for user interaction. That means that your blue box is on top, but its also means you can't click "Close" or "Add Element" on the other modal. (NOTE: You'll also notice the "Close/Add Element" dialog is greyed out -- you can override this by changing .new-element::backdrop{...} but it still won't the change the fact you can't click "Close" or "Add Element") Example here (with the backdrop removed)

enter image description here

  • Change the added element to dialog, call .show() when the element is appended, and change the click event for 'Open Dialog' to .show() instead of .showModal. This allows you to also click past the blue box (even though its 'on top'), but it also allows you to click anywhere on the page (kind of defeating the purpose of a modal). The ::backdrop pseudo element is also not available because you are not using .showModal If you take this approach you would need to attach closing the blue box to the "Close" click event handler. Example here

enter image description here

My recommendation is to either use a plugin for modals (such as Bootstrap's) or make your own with the functionality you want (using Javascript). Dialogs are technically experiential technology so it won't be easy trying to get the behavior you want out of the box. This is probably as close as you will get, though you could improve it by adding your own "backdrop".

Warbler answered 23/1, 2017 at 22:24 Comment(4)
This is exactly what I was looking for - thank you! I find it interesting how difficult it is to find much documentation even on the top layer concept considering it's been in Chrome since v37. I also wonder why the other browsers (save for Opera) are seemingly resistant to it.Shawannashawl
> To remove an element from a top layer, remove element from top layer hilarious 😆Alcuin
The first rule of top layer is: you do not talk about top layerAlcuin
This answer helped me figure out why I couldn't click the 'backdrop' to close my modal when I swapped from a div to a dialog. The answer was .show() over .showModal() in this case ❤️Muskrat

© 2022 - 2024 — McMap. All rights reserved.