Search code examples
javascriptkeyboardfocusaccessibilityonfocus

How to detect focus on link elements and form input fields when activated with Tab key?


I want to detect when user focuses a link or input field by pressing the Tab key. Does anyone know of a way to do this? I have tried using the onFocus event, but it does not seem to work.

(I am not using jQuery, and I want to detect focus on links as well, so the similar question 16144611 is not the same as this one.)


Solution

  • By combining keyUp and document.activeElement we can see if an element is currently focused.

    We then need to look for the Tab key on keyup and you have a reasonable start at a solution.

    const els = document.querySelectorAll('a, input');
    
    window.addEventListener('keyup', function(e){
       // check the key code
       const code = (e.keyCode ? e.keyCode : e.which);
       if(code == 9 && els.length){
         checkFocus();
       }
       
    });
    
    
    function checkFocus(){
       // loop all elements (within our selector at the start) and see if they match the document.activeElement  
       for (const el of els) {
         if(document.activeElement == el){
           console.log("focused tag:" + el.tagName);
         }
       }
    }
    <button>Click me for focus, I am not checked</button>
    <a href="#">Focused Link</a>
    <label for="input1">I am also reported</label>
    <input id="input1">
    <button>Another button not announced</button>

    Note that if you only ever want to check for links and inputs only a more efficient way to check would be:

    const els = ['A', 'INPUT'];
    
    window.addEventListener('keyup', function(e){
       // check the key code
       const code = (e.keyCode ? e.keyCode : e.which);
       if(code == 9 && els.length){
         checkFocus();
       }
       
    });
    
    
    function checkFocus(){
       // by checking the tagName we only have to do 2 loops no matter how many links or inputs there are on a page, which is far more efficient. The downside is it will check **every** link and input on the page. You would access the element with document.activeElelemnt instead if you need to know which item was focused.
       for (const el of els) {
         if(document.activeElement.tagName == el){
           console.log("focused tag:" + document.activeElement.tagName);
         }
       }
    }
    <button>Click me for focus, I am not checked</button>
    <a href="#">Focused Link</a>
    <label for="input1">I am also reported</label>
    <input id="input1">
    <button>Another button not announced</button>