I want to apply a transition
to dialog elements when they are opened, but my transition
attribute doesn't seem to be having any effect. Here's my code:
const dialog = document.querySelector("dialog");
document.querySelector("#open-button").addEventListener("click", () => {
dialog.showModal();
});
document.querySelector("#close-button").addEventListener("click", () => {
dialog.close();
});
button {
display: block;
}
dialog {
position: absolute;
top: 50px;
margin: auto;
padding: 0;
width: 50%;
height: 50%;
background-color: red;
opacity: 0;
-webkit-transition: opacity 2s ease-in, background-color 2s ease-in;
-o-transition: opacity 2s ease-in, background-color 2s ease-in;
transition: opacity 2s ease-in, background-color 2s ease-in;
}
dialog[open] {
background-color: green;
opacity: 1;
}
<button id="open-button">Open Dialog Element</button>
<dialog>
<button id="close-button">Close Dialog Element</button>
</dialog>
My intent is to slowly fade the dialog into view as its background visibly changes from red to green.
Instead, the rules of dialog[open]
are immediately applied? The MDN article doesn't mention transition
s or animations anywhere, implying this should work as any other element.
I am testing this in Firefox on Windows 10.
Your dialog transitions from display:none
to display:block
and that ruins transition
. The idea was to add dialog { display:block; }
but it turned out bad because the dialog is just hidden and reacts to the keyboard TAB navigation for example... So we need to keep a closed dialog display:none
.
So a couple of solutions:
animation
which I like since it's a pure CSS solution:dialog[open] {
animation: fadein 2s ease-in forwards;
}
@keyframes fadein{
0%{
opacity:0;
}
100%{
opacity:1;
background-color: green;
}
}
const dialog = document.querySelector("dialog");
document.querySelector("#open-button").addEventListener("click", () => {
dialog.showModal();
});
document.querySelector("#close-button").addEventListener("click", () => {
dialog.close();
});
button {
display: block;
}
dialog {
position: absolute;
top: 50px;
margin: auto;
padding: 0;
width: 50%;
height: 50%;
background-color: red;
opacity: 0;
}
dialog[open] {
animation: fadein 2s ease-in forwards;
}
@keyframes fadein{
0%{
opacity:0;
}
100%{
opacity:1;
background-color: green;
}
}
<button id="open-button">Open Dialog Element</button>
<dialog>
<button id="close-button">Close Dialog Element</button>
</dialog>
setTimeout
to allow the DOM to be re-rendered and remove it on the closing with your transition
left intact.setTimeout(()=>dialog.classList.add('open'));
dialog.addEventListener('close', () => dialog.classList.remove('open'));
The extra benefit of this approach that you can close the dialog with the transition also:
document.querySelector("#close-button").addEventListener("click", () => {
const close = e => e.propertyName === 'background-color' &&
dialog.close() ||
dialog.removeEventListener('transitionend', close);
dialog.addEventListener('transitionend', close);
dialog.classList.remove('open');
});
const dialog = document.querySelector("dialog");
dialog.addEventListener('close', () => dialog.classList.remove('open'));
document.querySelector("#open-button").addEventListener("click", () => {
dialog.showModal();
setTimeout(()=>dialog.classList.add('open'));
});
document.querySelector("#close-button").addEventListener("click", () => {
const close = e => e.propertyName === 'background-color' &&
dialog.close() ||
dialog.removeEventListener('transitionend', close);
dialog.addEventListener('transitionend', close);
dialog.classList.remove('open');
});
button {
display: block;
}
dialog {
position: absolute;
top: 50px;
margin: auto;
padding: 0;
width: 50%;
height: 50%;
background-color: red;
opacity: 0;
-webkit-transition: opacity 2s ease-in, background-color 2s ease-in;
-o-transition: opacity 2s ease-in, background-color 2s ease-in;
transition: opacity 2s ease-in, background-color 2s ease-in;
}
dialog.open {
background-color: green;
opacity: 1;
}
<button id="open-button">Open Dialog Element</button>
<dialog>
<button id="close-button">Close Dialog Element</button>
</dialog>