For the dialog element <dialog>
, is there some sort of "open" event that is fired when it is shown, either normally or as a modal?
The spec isn't totally clear on this, and MDN just lists a bunch of inherited events.
The close
event does fire, but I can't seem to get any sort of open
event.
Example HTML:
<dialog>
<h1>Oh hey, a dialog...</h1>
</dialog>
And in JavaScript:
document.querySelector('dialog').addEventListener('open', (e) => {
console.log(e);
});
document.querySelector('dialog').showModal();
For the dialog element <dialog>
, is there some sort of "open" event that is fired when it is shown, either normally or as a modal?
The spec isn't totally clear on this, and MDN just lists a bunch of inherited events.
The close
event does fire, but I can't seem to get any sort of open
event.
Example HTML:
<dialog>
<h1>Oh hey, a dialog...</h1>
</dialog>
And in JavaScript:
document.querySelector('dialog').addEventListener('open', (e) => {
console.log(e);
});
document.querySelector('dialog').showModal();
Share
Improve this question
asked Mar 6, 2018 at 2:37
BradBrad
163k55 gold badges377 silver badges552 bronze badges
3
-
Just a guess try
show
event? – Vinay Commented Mar 6, 2018 at 2:59 - @Viney Unfortunately, that event doesn't fire either. – Brad Commented Mar 6, 2018 at 17:10
- There seems to be some progress recently to rectify the situation github./whatwg/html/issues/9733 – Martin Commented Jul 3, 2024 at 14:49
4 Answers
Reset to default 72025 Update: beforetoggle
and toggle
events
This is now available via the beforetoggle
and toggle
events in Chromium v123: https://github./whatwg/html/pull/10091
Previous Answer:
No, there is no open
event.
The dialog has an open
property which can determine if it's opened or not, but unfortunately there's no event when this transitions.
An easy solution to your problem would be this :
<dialog id="dial">
<h3> dialog element </h3>
<button id="close">x</button>
</dialog>
<button id="buttonDialog" > Open </button>
<button id="buttonDialog2"> Open 2 </button>
const
dialog = document.getElementById('dial')
, close = document.getElementById('close')
, button = document.getElementById('buttonDialog')
, button2 = document.getElementById('buttonDialog2')
;
button.addEventListener('click', event => {
dialog.showModal()
})
close.addEventListener('click', event => {
dialog.close()
})
let observer = new MutationObserver(function() {
if (event[0].attributeName == 'open') console.log('updated')
});
observer.observe(dialog, { attributes: true })
;
button2.addEventListener('click', event => {
dialog.setAttribute('open', true)
})
As mentioned in the ments/anwers here, it is possible to generate this event using a MutationObserver().
As the answers here seem cruelly inplete (even wrong), I did my own experiments to pose an easily exploitable answer.
Nota :
_ <dialog>
JS objects always have an open
property, and it is a boolean value (true or false), even if this attribute is not present on the HTML declaration.
1st solution :
(() => // IIFE => add event 'dialog-open' to all Dialog elements
{
const
OpenEvent = new CustomEvent('dialog-open')
, ObserverM = new MutationObserver( recs =>
{
recs.forEach( ({attributeName: attr, target: dial }) =>
{
if (attr === 'open' && dial.open )
dial.dispatchEvent( OpenEvent );
})
});
document.querySelectorAll('dialog').forEach( dial =>
{
ObserverM.observe( dial, { attributes: true } );
})
})() // IIFE end...
const
btShowDial = document.querySelector('#bt-show_mDialog')
, dialogBox = document.querySelector('#dialog-box')
, dialBForm = document.querySelector('#dialog-box form')
;
btShowDial.onclick =_=>
{
dialogBox.showModal()
}
dialogBox.addEventListener('dialog-open', () =>
{
dialBForm.inNum.valueAsNumber = 0 | Math.random() *10**4
dialogBox.returnValue = 'exit with Escape key'
})
dialogBox.onclose=_=>
{
console.log(`${dialBForm.inNum.value } is ${dialogBox.returnValue}` )
}
<button id="bt-show_mDialog">show modal dialog..</button>
<dialog id="dialog-box">
<form method="dialog">
<h3>Dialog -1-</h3>
<label> mumeric : <input type="number" name="inNum"></label>
<br>
<button value="good"> good </button>
<button value="bad" > bad </button>
</form>
</dialog>
Personally, I prefer to use their event methods directly on DOM Objects.
They have the advantage of being unique, and of making the code more readable.
so might as well add this one, rather than creating a specific custom event!
2nd solution :
(() => // IIFE => add event 'dialog-open' to all Dialog elements
{
const Dialogs = document.querySelectorAll('dialog');
Dialogs.forEach( dial => dial.onOpen = function(){} ) // add onOpen empty method.
const ObserverM = new MutationObserver( recs =>
{
recs.forEach( ({attributeName: attr, target: dial }) =>
{
if (attr === 'open' && dial.open ) dial.onOpen(); // call onOpen Method...
})
});
Dialogs.forEach( dial => ObserverM.observe( dial, { attributes: true }))
})() // IIFE end...
const
btShowDial = document.querySelector('#bt-show_mDialog')
, dialogBox = document.querySelector('#dialog-box')
, dialBForm = document.querySelector('#dialog-box form')
;
btShowDial.onclick =_=>
{
dialogBox.showModal()
}
dialogBox.onOpen =_=>
{
dialBForm.inNum.valueAsNumber = 0 | Math.random() *10**4
dialogBox.returnValue = 'exit with Escape key'
}
dialogBox.onclose=_=>
{
console.log(`${dialBForm.inNum.value } is ${dialogBox.returnValue}` )
}
dialog::backdrop {
background: #00ddff5d;
}
<button id="bt-show_mDialog">show modal dialog..</button>
<dialog id="dialog-box">
<form method="dialog">
<h3>Dialog -1-</h3>
<label> mumeric : <input type="number" name="inNum"></label>
<br>
<button value="good"> good </button>
<button value="bad" > bad </button>
</form>
</dialog>
Found this thread and wanted to post my solution: custom event.
After setting a document.querySelector('dialog').showModal();
call you can add a document.querySelector('dialog').dispatchEvent(new Event('open'));
. Then the expected document.querySelector('dialog').addEventListener('open', e => {...});
works!