Search code examples
javascriptjqueryinputdisableautofocus

Autofocus following tabindex and skip disabled fields


How does the cursor automatically hops to the next possible (not disabled) input field according to tabindex?

I got that function (source: Focus Next Element In Tab Index ) but my cursor doesn't move automatically after input of 1 value: - Why?

function focusNextElement () {
//add all elements we want to include in our selection
var focussableElements = 'a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])';
if (document.activeElement && document.activeElement.form) {
    var focussable = Array.prototype.filter.call(document.activeElement.form.querySelectorAll(focussableElements),
    function (element) {
        //check for visibility while always include the current activeElement 
        return element.offsetWidth > 0 || element.offsetHeight > 0 || element === document.activeElement
    });
    var index = focussable.indexOf(document.activeElement);
    if(index > -1) {
       var nextElement = focussable[index + 1] || focussable[0];
       nextElement.focus();
    }                    
}
}

Example for my input fields:

<table>
<thead></thead>
<tbody>
<tr>
<td> 1<input type="text" maxlength="1" oninput="focusNextElement(this)" id="a" name="a" tabeindex="1">.   </td>
 <td>3<input type="text" maxlength="1" oninput="focusNextElement(this)" id="b" name="b" tabeindex="3" disabled></td>
 <td>5<input type="text" maxlength="1" oninput="focusNextElement(this)" id="c" name="c" tabeindex="5"></td></tr>
 <tr>
 <td>2 <input type="text" maxlength="1" oninput="focusNextElement(this)" id="d" name="d" tabeindex="2"></td>
 <td>4<input type="text" maxlength="1" oninput="focusNextElement(this)" id="e" name="e" tabeindex="4"></td>
 <td>6<input type="text" maxlength="1" oninput="focusNextElement(this)" id="f" name="f"  tabeindex="6""></td>
 </tr>
 </tbody>
 </table>

Example on: https://jsfiddle.net/rydjnzkw/4/


Solution

  • You don't most of this code, just querySelector the inputs which are not disabled, try to find the current element index in this array, and focus the next element.

    const inputs = document.querySelectorAll('input:not([disabled])')
    
    function focusNextElement (input) {
      const nextIndex = [...inputs].findIndex(i => i === input) + 1
      if (inputs[nextIndex]) {
        inputs[nextIndex].focus()
      }
    }
    <input type="text" maxlength="1" oninput="focusNextElement(this)" id="a" name="a">
    <input type="text" maxlength="1" id="c" name="b" disabled>
    <input type="text" maxlength="1" oninput="focusNextElement(this)" id="d" name="c">

    UPDATE

    To make it work according to tabeindex

    const inputs = document.querySelectorAll('input:not([disabled])');
    let focusableElement;
    let maxTries = 100;
    let counter = 0;
    const getNextElement = (tabeindex) => {
      const element = document.querySelector(`[tabeindex="${tabeindex + 1}"]`)
      if (counter >= maxTries) {
        return;
      }
      if (element && !element.disabled) {
        counter = 0;
        focusableElement = element;
        return;
      }
      counter++
      getNextElement(tabeindex + 1)
    }
    
    function focusNextElement (input) {
      const nextIndex = [...inputs].findIndex(i => i === input) + 1
      const tabeindex= +input.getAttribute('tabeindex');
      const element = getNextElement(tabeindex)
      focusableElement.focus()
    }
    <table>
    <thead></thead>
    <tbody>
    <tr>
     <td> 1<input type="text" maxlength="1" oninput="focusNextElement(this)" id="a" name="a" tabeindex="1"></td>
     <td>3<input type="text" maxlength="1" oninput="focusNextElement(this)" id="b" name="b" tabeindex="3" disabled></td>
     <td>5<input type="text" maxlength="1" oninput="focusNextElement(this)" id="c" name="c" tabeindex="5">
    </td></tr>
    <tr>
     <td>2 <input type="text" maxlength="1" oninput="focusNextElement(this)" id="d" name="d" tabeindex="2"></td>
     <td>4<input type="text" maxlength="1" oninput="focusNextElement(this)" id="e" name="e" tabeindex="4"></td>
     <td>6<input type="text" maxlength="1" oninput="focusNextElement(this)" id="f" name="f"  tabeindex="6""></td>
    </tr>
    </tbody>
    </table>