Reputation: 29453
The <dialog>
element is now cross-browser compatible (since March 2022).
I tried my hand at it today and familiarised myself with:
HTML
<dialog>
JavaScript
.show()
.showModal()
.close()
CSS
::backdrop
Everything seems straightforward but the one thing I've been unable to achieve so far is: fading up the backdrop.
For instance, if I want the final color of the backdrop to be:
background-color: rgba(0, 0, 63, 0.8);
but have it transition
(or animate
) to that background-color
from:
background-color: rgba(0, 0, 0, 0);
is this even possible?
Here is my (non-working) example:
const myButton = document.querySelector('button');
const myDialog = document.querySelector('dialog');
const requestDialog = () => {
myDialog.showModal();
setTimeout(() => myDialog.classList.add('fadeUp'), 400);
}
myButton.addEventListener('click', requestDialog, false);
body {
display: flex;
justify-content: center;
align-items: center;
height: 180px;
}
button {
position: absolute;
top: 6px;
left: 6px;
cursor: pointer;
}
dialog::backdrop {
background-color: rgba(0, 0, 0, 0);
transition: backgroundColor 0.6s ease-out;
}
dialog.fadeUp::backdrop {
background-color: rgba(0, 0, 63, 0.8);
}
<button type="button">Click me to<br />Request Dialog</button>
<dialog>
<h2>My Dialog</h2>
</dialog>
Upvotes: 13
Views: 9804
Reputation: 51
So I wrote this function, it works fine in my chrome
function getDialog(selector) {
const dialog = selector ? document.querySelector(selector) : document.createElement('dialog')
const oldShow = dialog.showModal
dialog.showModal = () => {
oldShow.call(dialog)
dialog.classList.add('show')
}
const oldClose = dialog.close
dialog.close = () => {
dialog.addEventListener('transitionend', () => oldClose.call(dialog), {once: true})
dialog.classList.remove('show')
}
return dialog
}
const dialog = getDialog('dialog')
const showBtn = document.getElementById('show-btn')
showBtn.addEventListener('click', () => dialog.showModal())
const closeBtn = document.getElementById('close-btn')
closeBtn.addEventListener('click', () => dialog.close())
dialog {
opacity: 0;
transition: opacity 0.5s ease;
}
dialog.show {
opacity: 1;
}
dialog::backdrop {
background-color: #00000000;
transition: background-color 0.5s ease;
}
dialog.show::backdrop {
background-color: #00000088;
}
<button id="show-btn">show</button>
<dialog>
<p>hello :)</p>
<button id="close-btn">close</button>
</dialog>
--- edit ---
Thanks @Destroy666 for the reminder, this is my first answer on stackoverflow, I still have a lot to do, The following is additional information:
Compared to @G-Cyrillus and @YoshiJL 's answer:
::backdrop
selector instead of box-shadow
alternative, which is more intuitive.Compared to @Adriano 's answer:
I use transition
instead of @keyframes
animation, which avoids the problem of not playing the complete animation caused by closing the dialog before the animation ends.
Also works fine on Firefox.
In addition:
Upvotes: 5
Reputation: 31
G-Cyrillus's answer is almost perfect! Just added the use of max
to the box-shadow so that the shadow will cover on mobile devices.
box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0);
https://stackoverflow.com/a/71764440/19130936
Upvotes: 3
Reputation: 105863
If you use a box-shadow
, it might work and be close enough to what you try to do :
dialog {
box-shadow: 0 0 0 100vw rgba(0, 0, 0, 0);
transition: 2s ease-out;
}
dialog.fadeUp {
box-shadow: 0 0 0 100vw rgba(0, 0, 63, 0.8);
transition: 2s ease-out;
}
Upvotes: 6
Reputation: 71
I was having the same problem but this solved to me.
const dialog = document.querySelector('.modal')
function openModal() {
dialog.showModal(); // default dialog method
}
function closeModal() {
dialog.classList.add('close'); // run animation here
dialog.addEventListener('animationend', () => {
dialog.classList.remove('close')
dialog.close(); // then run the default close method
}, {once : true}); // add this to prevent bugs when reopening the modal
}
.modal {
display: none;
}
/* when the dialog is open by its default method it adds a open tag on the element */
.modal[open] {
display: flex;
}
.modal[open]::backdrop {
animation: backdrop-fade 2s ease forwards;
}
.modal.close::backdrop {
animation: backdrop-fade 3s ease backwards;
animation-direction: reverse;
}
@keyframes backdrop-fade {
from {
background: transparent;
}
to{
background: rgba(0,0,0);
}
}
<button onclick="openModal()">open modal</button>
<dialog class="modal">
<button onclick="closeModal()">close modal</button>
</dialog>
Upvotes: 7