javascripthtmlgoogle-chromefocus

HTML dialog focusing button element when opened


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)


Solution

  • 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>