1

I currently have a <dialog> which I am opening via JS. For demonstration purposes, my dialog has a single <button> element within it.

My issue is, when I open the dialog using .showModal(), the button within the modal gets focused for some reason. See example of issue below:

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">&times;</button>
</dialog>

As you can see, when the dialog is opened, the background of the button within the dialog gets the :focus styles applied, showing that it is focused.

My question is: Why is this happening? My expected behaviour would be for the dialog to open and for the button to not be focused when opening the dialog. I'm aware that I can .blur() the close button programatically, but that feels like I'm just "hiding" the issue rather than addressing the thing that's actually causing it.

Note: This issue is present in the latest version of Google Chrome (Version 81.0.4044.138)

Shnick
  • 1,199
  • 1
  • 13
  • 32

3 Answers3

3

This is seems default behavior defined in the standard to focus the modal subtree once its rendered, from the HTML live standard:

  1. Run the dialog focusing steps for subject.

If you want to keep it like this and prevent the button from focus just trigger blur() event on the button, I tried to use inert and autofocus attributes but they doesn't seems to work work, so I think you have to stick with .blur() implementation:

const dialog = document.querySelector("#dialog");
document.querySelector("#open-btn").addEventListener('click', () => {
  dialog.showModal();
  document.getElementById('close-btn').blur();
});

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="false" autofocus="false">&times;</button>
</dialog>
ROOT
  • 11,363
  • 5
  • 30
  • 45
  • While I didn't want to resort to blur(), you explained the reasoning behind why this happens well enough for me to accept your answer. I didn't realize that this was intended default behaviour and seems like something I've just got to manage through JS. Thanks :) – Shnick May 21 '20 at 01:48
0

Outline property added by webkit

Above snapshot is captured from the style section of the close-btn after opening the dialog box (developer tools of the browser/simply press F12 key to open it).

Webkit of browser is adding outline property explicitly when the dialog box is opened.

The outline property provides visual feedback for links that have "focus" when navigating a web document using the TAB key (or equivalent). This is especially useful for folks who can't use a mouse or have a visual impairment. If you remove the outline you are making your site inaccessible for these people.

But if you still want to remove it, then use below code.

#close-btn {
  background: red;
  outline: none;
}

I hope this will help you

srp
  • 619
  • 7
  • 18
  • thanks for the answer :). I'm mainly looking for a way of _preventing_ the button from being focused in the first place. I'd also like to know why this would be default behaviour, it seems strange to me. Nonetheless, thanks again for your answer – Shnick May 17 '20 at 11:21
0

You can simply do a focus() followed by an immeridate blur() on some arbitrary element.

For example -

const dialog = document.querySelector("#dialog");
document.querySelector("#open-btn").addEventListener('click', () => {
  dialog.showModal();
  dialog.focus();
  dialog.blur();
});

In the above example I chose to focus and blur on the dialog element itself - that's enough to counteract the default autofocus behavior. Works on Chromium-based browsers.

Arik
  • 5,266
  • 1
  • 27
  • 26