How can the HTML <dialog> element be positioned according to normal flow when opened with showModal?
Asked Answered
C

3

10

When using a <dialog> element with .show() it is positioned according to normal position etc. CSS properties.

Is it possible to have that same positioning with .showModal()?

Even when using

dialog:modal {
  margin: 0;
  position: relative;
}

to override the browsers position: fixed the dialog ends up in the top left corner (checked with chromium and firefox).

EDIT: copying my comment here for better visibility and avoid more answers about CSS tweaking:

I know how to do computations and move the thing around with top and left. But this is what I would like to avoid.

Meaning I would like to just rip it out of the hands which hold it back as if position:fixed.

const button = document.getElementById('button');
const b2 = document.getElementById('b2');
const dialog = document.getElementById('dialog');
button.addEventListener('click', () => {dialog.showModal();});
b2.addEventListener('click', () => {dialog.show();});
dialog.addEventListener('click', () => {dialog.close();});
#dialog:modal, #dialog {
  margin: 0;
  position: relative;
}
#wrapper {
  background: #fafafa;
  position: relative;
}
<button id="button">open modal</button>
<button id="b2">just show</button>
<div id="wrapper">
  <div>Some context below which the dialog should appear.</div>
  <dialog id="dialog">click to close</dialog>
</div>
Cankerworm answered 2/10, 2022 at 10:56 Comment(2)
Do you need it to take up space in the layout?Pizza
I think I can deal with anything that shows how to rip it out of the hands which hold it back as if position:fixed. Ultimately I don't want it to take space, but overlay the page like modal, just at the "right" position. I think I know how to do computations and move the thing around with top and left. But this is what I would like to avoid.Cankerworm
L
8

edited 04.03.24; thanks to JGC

Answer

Since the <dialog> element is in it's own layer (see this answer for more information) in relation to the rest of the DOM, it isn't possible to set it as inline, which I understood to be the question.

Positioning <dialog> in general

Also leaving this here for anyone searching for how to position dialogs: SebastianZ mentions in this comment, that the dialog is centered using margin: auto by default. Deactivating margins therefore allows positioning the dialog using absolute coordinates i. e. with top and left.

Example of a centered top dialog:

dialog {
 margin: 0; /* `margin: auto;` is the default. */
 transform: translateX(-50%);
 left: 50%;
}
<dialog open>
Foo
</dialog>

or, if you don't need full control and just want to center the modal at the top of the page:

dialog {
 margin-top: 0;
}
<dialog open>
Foo
</dialog>
Lalia answered 13/12, 2023 at 10:43 Comment(1)
SebastianZ's comment is correct, but I found it quite misleading. In Safari at least, I can only set it to 0 or I can't set it. Better to say "setting margin: 0; means that instead of the dialog's origin being in the center of the window, it is then at top left. This allows top: and left: values to be set as expected.Mimi
P
7

I hope you find a CSS-only solution, but if you put the dialog in a wrapper div, you can use that div's position to absolutely position the dialog when you show it:

#dialog {
    margin: 0;
    position: absolute;
}
<div id="dialog-wrapper">
    <dialog id="dialog">click to close</dialog>
</div>
button.addEventListener("click", () => {
    const wrapper = document.getElementById("dialog-wrapper");
    dialog.style.left = wrapper.offsetLeft + "px";
    dialog.style.top = wrapper.offsetTop + "px";
    dialog.showModal();
});

Live Example:

const button = document.getElementById("button");
const b2 = document.getElementById("b2");
const dialog = document.getElementById("dialog");
button.addEventListener("click", () => {
    const wrapper = document.getElementById("dialog-wrapper");
    dialog.style.left = wrapper.offsetLeft + "px";
    dialog.style.top = wrapper.offsetTop + "px";
    dialog.showModal();
});
b2.addEventListener("click", () => {
    dialog.show();
});
dialog.addEventListener("click", () => {
    dialog.close();
});
#dialog {
    margin: 0;
    position: absolute;
}
<button id="button">open modal</button>
<button id="b2">just show</button>
<div>
    <div>Some context below which the dialog should appear.</div>
    <div id="dialog-wrapper">
        <dialog id="dialog">click to close</dialog>
    </div>
</div>
Pizza answered 2/10, 2022 at 11:8 Comment(2)
Yes, it was that manual positioning that I tried to avoid, but it is probably the easiest without losing other benefits of modal. I guess the top layer verbiage found in html.spec.whatwg.org/multipage/… has something to do with it. Where the top layer linked there says things like If its position property computes to fixed, its containing block is the viewport, and the initial containing block otherwise. and for the last two I can't even tell the difference.:-/Cankerworm
Depending on use case, when scrolling is involved the positions need adjustment. In my use case I just close() the dialog when the user starts scrolling.Cankerworm
B
3

Try using margin-right: 0;, and set width and height as needed. It worked for me ! No need for position: it is set to fixed. The dialog is then anchored to the right of the window.

Blalock answered 24/8, 2023 at 14:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.