As I am aware, the showModal()
method runs the following steps which end up focusing elements within an HTML dialog (emphasis mine) :
Let subject be the dialog element on which the method was invoked.
If subject already has an open attribute, then throw an "InvalidStateError" DOMException.
If subject is not connected, then throw an "InvalidStateError" DOMException`.
Add an open attribute to subject, whose value is the empty string.
Set the dialog to the centered alignment mode.
Let subject's node document be blocked by the modal dialog subject.
If subject's node document's top layer does not already contain subject, then add subject to subject's node document's top layer.
Run the dialog focusing steps for subject.
So the last step, 8
, will run the following dialog focusing steps on the dialog. From my understanding (which could be completely wrong), these three steps from the dialog focusing-steps section of the spec specify that the element should only be focused if the element is not inert and is auto-focusable:
If subject is inert, return.
Let control be the first descendant element of the subject, in tree order, that is not inert and has the autofocus attribute specified.
If there isn't one, then let control be the first non-inert descendant element of subject, in tree order.
If there isn't one of those either, then let control be subject.
Run the focusing steps for control.
...
So, to me, it seems as though if my button below (see snippet) has the inert
attribute or is not auto-focusable then it shouldn't get focused when the dialog opens. However, when I try and apply both attributes, it still ends up being focused.
Attempt with the inert
boolean attribute (which I thought would've made the dialog focusing steps return above, hence performing no focusing):
const dialog = document.querySelector("#dialog");
document.querySelector("#open-btn").addEventListener('click', () => {
dialog.showModal();
});
document.querySelector("#close-btn").addEventListener('click', () => {
dialog.close();
});
#close-btn:focus {
background: red;
}
<button id="open-btn">Open</button>
<dialog id="dialog">
<button id="close-btn" inert="inert">×</button>
</dialog>
Attempt with the autofocus
boolean attribute set to false (I believe this is how you set it to false, I also tried autofocus="false"
which didn't work either):
update 2023: It appears the below hidden snippet using inert
now does stop the button from being autofocused (when I asked this question it didn't, which I suspect was a chrome bug), however it stops the button from being clickable, so this isn't a valid option.
const dialog = document.querySelector("#dialog");
document.querySelector("#open-btn").addEventListener('click', () => {
dialog.showModal();
});
document.querySelector("#close-btn").addEventListener('click', () => {
dialog.close();
});
#close-btn:focus {
background: red;
}
<button id="open-btn">Open</button>
<dialog id="dialog">
<button id="close-btn" autofocus="">×</button>
</dialog>
With both of these failing to work, I searched SO and found this answer which suggested that I might also be able to use tabindex="-1"
, which didn't work either.
I'm aware that I can blur the button once it is focused using .blur()
, but my question specifically is:
- Why don't the two fiddles above disable the button from being automatically focused?
- Is there an HTML attribute of some sort that I can use to stop my button from being focused?