O dialog focus, where art thou?

posted on and updated on

Here’s a job interview question for you: When you click a button and call the showModal() method to open a modal <dialog>, where does the focus go by default, and how can you move it elsewhere?

Don't know the answer? Neither did I, so I tested it.

Update: I tested this again on October 13, 2025 and the results are very consistent now. Demo 6 and Demo 10 are the only exceptions.

OS/Browsers

macOs 15.6.1
Chrome 144
Firefox 144
Safari 18.6

Here’s a Codepen with all demos so you can follow along.

Results from my original test on 17.07.2023

OS/Browsers

macOs 13.4.1 Ventura
Chrome 114
Firefox 115
Safari 16.5.1

Here’s a Codepen with all demos so you can follow along.

Demo 1: Dialog with no interactive element

<button>demo 1</button>

<dialog>
  <h1>Demo 1</h2>
</dialog>
document.addEventListener('click', e => {
  if (e.target.closest('button')) {
    e.target.nextElementSibling.showModal()
  }
})

Focus is on:

Chrome: dialog
Firefox: body
Safari: body

Demo 2: Dialog with interactive elements

<button>demo 2</button>

<dialog>
  <h1>Demo 2</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 3: Dialog with interactive elements and close button first


<button>demo 3</button>

<dialog>
  <form method="dialog">
    <button>close</button>
  </form>

  <h1>Demo 3</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: close button
Firefox: close button
Safari: first focusable element after close button

Demo 4: Dialog with interactive elements and close button last

<button>demo 4</button>

<dialog>  
  <h1>Demo 4</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>

  <form method="dialog">
    <button>close</button>
  </form>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 5: Dialog without interactive elements and autofocus on dialog

<button>demo 5</button>

<dialog autofocus>
  <h1>Demo 5</h2>
</dialog>

Focus is on:

Chrome: dialog
Firefox: body
Safari: body

Demo 6: Dialog with interactive elements and autofocus on dialog

<button>demo 6</button>

<dialog autofocus>
  <h1>Demo 6</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 7: Dialog with autofocus on last interactive element

<button>demo 7</button>

<dialog>
  <h1>Demo 7</h2>

  <button>First focusable element</button>
  <a href="#" autofocus>Last focusable element</a>
</dialog>

Focus is on:

Chrome: last focusable element
Firefox: last focusable element
Safari: last focusable element

Okay, so far, so inconsistent. The specs says “The tabindex attribute must not be specified on dialog elements.”.

I won't do what you tell me.

– Rage Against the Machine

Demo 8: Dialog with tabindex and no interactive element

<button>demo 8</button>

<dialog tabindex="-1">
  <h1>Demo 8</h2>
</dialog>

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Demo 9: Dialog with tabindex and interactive elements

<button>demo 9</button>

<dialog tabindex="-1">
  <h1>Demo 9</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 10: Dialog with tabindex, autofocus, and interactive elements

<button>demo 10</button>

<dialog tabindex="-1" autofocus>
  <h1>Demo 10</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 11: Dialog with tabindex, focus(), and interactive elements

<button>demo 11</button>

<dialog tabindex="-1">
  <h1>Demo 11</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>
dialog.showModal()
dialog.focus()

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Conclusion

The answer is: It depends. It depends on several factors:

  • The browser you're using.
  • The presence of interactive elements.
  • The presence of a dialog close button.
  • The presence of the autofocus attribute.
  • The presence of the tabindex attribute.

There was a lot of discussion on how browsers should handle focus in modal dialogs. They finally concluded and summarized the rules in the spec earlier this year. If I read it right, Chrome is the only browser that follows most rules correctly at this point. Other browsers will likely follow soon.

Right now you get the most consistent behaviour when:

  • you have interactive elements and do nothing
  • you put the autofocus attribute on one of the interactive elements
  • you put tabindex=-1 on the dialog (and focus() it).

Demo 1: Dialog with no interactive element

<button>demo 1</button>

<dialog>
  <h1>Demo 1</h2>
</dialog>
document.addEventListener('click', e => {
  if (e.target.closest('button')) {
    e.target.nextElementSibling.showModal()
  }
})

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Demo 2: Dialog with interactive elements

<button>demo 2</button>

<dialog>
  <h1>Demo 2</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 3: Dialog with interactive elements and close button first


<button>demo 3</button>

<dialog>
  <form method="dialog">
    <button>close</button>
  </form>

  <h1>Demo 3</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: close button/first focusable element
Firefox: close butto/first focusable elementn
Safari: close button/first focusable element

Demo 4: Dialog with interactive elements and close button last

<button>demo 4</button>

<dialog>  
  <h1>Demo 4</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>

  <form method="dialog">
    <button>close</button>
  </form>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 5: Dialog without interactive elements and autofocus on dialog

<button>demo 5</button>

<dialog autofocus>
  <h1>Demo 5</h2>
</dialog>

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Demo 6: Dialog with interactive elements and autofocus on dialog

<button>demo 6</button>

<dialog autofocus>
  <h1>Demo 6</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: dialog
Safari: dialog

Demo 7: Dialog with autofocus on last interactive element

<button>demo 7</button>

<dialog>
  <h1>Demo 7</h2>

  <button>First focusable element</button>
  <a href="#" autofocus>Last focusable element</a>
</dialog>

Focus is on:

Chrome: last focusable element
Firefox: last focusable element
Safari: last focusable element

Demo 8: Dialog with tabindex and no interactive element

<button>demo 8</button>

<dialog tabindex="-1">
  <h1>Demo 8</h2>
</dialog>

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Demo 9: Dialog with tabindex and interactive elements

<button>demo 9</button>

<dialog tabindex="-1">
  <h1>Demo 9</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Focus is on:

Chrome: first focusable element
Firefox: first focusable element
Safari: first focusable element

Demo 10: Dialog with tabindex, autofocus, and interactive elements

<button>demo 10</button>

<dialog tabindex="-1" autofocus>
  <h1>Demo 10</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>

Chrome: first focusable element
Firefox: dialog
Safari: dialog

Demo 11: Dialog with tabindex, focus(), and interactive elements

<button>demo 11</button>

<dialog tabindex="-1">
  <h1>Demo 11</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>
dialog.showModal()
dialog.focus()

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Demo 12: Dialog with focus(), and interactive elements and no tabindex

<button>demo 12</button>

<dialog>
  <h1>Demo 12</h2>

  <button>First focusable element</button>
  <a href="#">Last focusable element</a>
</dialog>
dialog.showModal()
dialog.focus()

Focus is on:

Chrome: dialog
Firefox: dialog
Safari: dialog

Conclusion

Generally, the behaviour is now very consistent. There are only differences in Demo 6 and Demo 10. When you put autofocus on a dialog that contains interactive elements, Safari and Firefox put focus on the dialog, but Chrome puts it on the first focusable element.

Updates

: Changed body to first focusable element for Chrome in demo 6 and demo 10. I had experimental web platform features enabled, which changed the current default behaviour.

: Tested everything again.