Problem/Motivation

When opening an entity browser modal, the user is not always able to access the iframe via tab on the keyboard. Instead they get trapped on the close button.

Proposed resolution

Easiest solution I could find is to set tabindex="0" on the iframe when displaying the modal.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jayhuskins created an issue. See original summary.

jayhuskins’s picture

StatusFileSize
new576 bytes

Here is a small patch that simple adds tabindex="0" to the iframe when displaying a modal

mohit.bansal623’s picture

Status: Active » Needs review
StatusFileSize
new576 bytes
Anonymous’s picture

Hello,

I have managed to replicate this issue and I agree that it would be nice if users could use tab key to navigate the iframe in modal widget.
The patch appended in #2 and #3 are identical the only difference being that the tests weren't run on the patch in comment #2.

After applying the patch the iframe in modal entity browser becomes accessible using the tab key, but the close button can no longer be accessed by using tab key. The only way tab cycles to close button if I click on the title part of the modal window.

Tested this using Chrome and Firefox browsers and Drupal 8.9.11 and 9.2.x-dev.

jayhuskins’s picture

igork96’s picture

Tested it and I can confirm that is working, just like #4 said the close button can no longer be accessed by using the tab key.

dsnopek’s picture

This is similar to this issue for Media in D7:

https://www.drupal.org/project/media/issues/2914241

The fix there added some Javascript to allow the tab to jump back up to the close button once focus got to the end of the iframe.

I'll see if I can implement something similar here!

dsnopek’s picture

StatusFileSize
new1.89 KB

This patch ports the JS from D7's media module, allowing the user to TAB out of the iframe, back to the close button on the modal.

dsnopek’s picture

StatusFileSize
new2.27 KB

I found an issue that only affected tabbing backwards. This latest patch fixes it!

dsnopek’s picture

StatusFileSize
new2.55 KB

New patch fixes another related issue: currently, if you TAB to the "Browse" button (the one that opens the modal) and press ENTER, the focus will momentarily move to the modal, and then be sucked back to the "Browse" button which is under the model.

With the patch, the focus will move into the modal (although, not in the most ideal place - it focuses the iframe itself, when it'd be better on it's first child or the modal's close button).

dsnopek’s picture

StatusFileSize
new2.72 KB

Alright, this is hopefully my last patch before getting some review :-)

In this version, it starts keyboard focus on the modal's close button when it opens, and allows focus to freely flow through the elements on the iframe and back up to the close button (both TAB'ing forward and SHIFT TAB'ing backwards).

I think this is everything necessary to say the modal iframe is tab accessible :-)

Status: Needs review » Needs work

The last submitted patch, 11: entity_browser-keyboard-trap-3191302-11.patch, failed testing. View results

silvi.addweb’s picture

Status: Needs work » Needs review
StatusFileSize
new2.77 KB

Re-roll the patch #11 according to the latest code changes.

benstallings’s picture

Status: Needs review » Needs work

Claude Code says:

Observations

Cross-origin concern: iframe.contentDocument.body will throw a security error if the iframe content is served from a different origin. Entity browser iframes are same-origin in normal usage, but this should be noted. A try/catch around the contentDocument access would make it resilient.

.get(0).focus() without null check — If there are no tabbable elements (e.g., empty view results), .get(0) returns undefined and .focus() throws. Both the :tabbable:last redirect (line 94) and the initial close button focus (line 84) could hit this. Using .first().trigger('focus') would be safer.

once() usage is correct — Guards against duplicate event binding if the iframe reloads (e.g., pager navigation within the browser).

File mode change to 755 — Both files change from 644 to 755. Executable permission on PHP/JS files is unnecessary and may trigger security scanners. Likely accidental from the contributor's environment.

Verdict

This is a well-designed accessibility fix solving a genuine keyboard trap issue. The focus cycling logic is sound and follows established dialog a11y patterns. Would merge after: (1) removing the file mode changes, (2) adding null safety on .get(0).focus() calls, and (3) optionally adding a try/catch around contentDocument access.

benstallings’s picture

Version: 8.x-2.5 » 8.x-2.x-dev
Assigned: Unassigned » benstallings

benstallings’s picture

Assigned: benstallings » Unassigned
Status: Needs work » Needs review