Pass focus from an iframe to next focusable element in host page
Tags: html, javascript
Published: 2022-03-24 15:49:29

This question was originally asked by [GOBLiN](https://stackoverflow.com/users/3892498/g0blin) on [Stackoverflow](https://stackoverflow.com/questions/71465930/how-to-pass-focus-from-an-iframe-to-next-focusable-element-in-host-page/71604242#71604242). I quite enjoyed answering this question, so I thought why not share the process with you guys here?
Here's the main snipped from his question
Question: After the iframe receives focus and a new tab keypress is detected, how can I pass the focus to the host page's next focusable element?
------------
Simple example:
```
<!-- host page -->
<button> first button </button>
<iframe src="myIframeWidget.com"/>
<button> second button </button>
```
In the above, if the first button is focused, then the expected behavior is that on first tab the iframe will receive focus, and on the next tab the second button will receive focus (skipping all focusable elements inside the iframe).

Once the iframe is focused and tab is pressed, I need to pass the focus from my iframe to the second button.

And Here's how I went for the solution.
-------------

Let's say, this is the content of the host page
```
<button>Main button 1</button>
<button>Main button 2</button>
<iframe id="frame1" name="frame1" src="iframe.html"></iframe>
<button>Main Button 3</button>
```
Now, when you receive the focus on the iframe, which is `iframe.html`, on the next tab press, you want to pass the focus to the `Main Button 3` button. You might have a lot of focusable content on your `iframe.html` like,
```
<button>I frame button 1</button>
<button>I frame button 2</button>
```
that you want to skip. To do that, you can write a simple javascript inside your `iframe.html` Which is,
```
let go_next = false;
document.body.addEventListener('keyup', (e)=> {
    if( e.which == 9 ) {
        if(go_next){
            window.parent.document.getElementById('frame1').nextElementSibling.focus()
            go_next=false
        }else{
            go_next =true;
        }
    }
});
```

**Code Explanation**

We don't want the focus to immediately pass to the next element, as the user should be able to focus on the iframe as well. For that reason, the script is assuming that the user has focused on the iframe for the first time by declaring variable `go_next = false`

***Note: Focusing from `Main Button 2` to iframe is counted as a tab press inside the iframe.html. That's why we have to ignore the first tab press inside the iframe.html***

So, just after the user has focused on the iframe, we're making our variable `go_next = true`. Now on the next tab press, we can proceed to pass the focus to the next element of the host page.

To do that, we are grabbing the host page using `window.parent` and selecting the iframe from the host page using `document.getElementById('frame1')` and the next element of the iframe using `nextElementSibling` and focusing the next element using the focus function. And after passing the focus, we're making the `go_next = false` again for the next time.

I've prepared a small demonstration for you to test [here](https://apps.blogdesire.com/iframe/)



Alternative Solution For Cross Domains
--------------------------------------
Cross domains often block access to the parent host using *Content Script Policy*.
To overcome this issue, we have to play a bit tricky. 
We're are going to create an invisible button at the end of our `iframe.html` page. Eg: 
```
<button id="last_element" style="opacity:0;filter:alpha(opacity=0);">Hello</button>
```
Remember we said the tab press that was used to focus the iframe can be accessed inside the iframe.html?
Well, we're going to take that advantage and focus on the last button of our `iframe.html`. To do that, add this script at the end of the `iframe.html`
```
document.body.addEventListener('keyup', (e)=> {
    if( e.which == 9 ) {
        document.querySelector("#last_element").focus()
    }
});
```
Now, as the last element of the iframe is focused, the next focus will be always the next element of the host page.
Here's a demo on [codepen](https://codepen.io/md-khokon/pen/VwyPbaR)