12

I am implementing progressive UI disclosure pattern in my application. Using which I am disabling the next elements. So based on input of one element the next element is enabled.

But I have a problem is since the next element is disabled, the tab from the current element is taking the focus to the end of document or the tab header when tab out. As the progressive enables the element after the tab out, while this was happening the next element was not enabled so tab was lost outside the document.

So my requirement is to enable tab on the disabled elements and also on mobile/tablet devices the click events should at least be registered on the disabled elements. Please let me know your views on this.

IndianWebDeveloper
  • 129
  • 1
  • 1
  • 4

5 Answers5

6

Answer

To answer the question (as we already discussed in the comments), disabled elements can't be focused.

Workaround

For those looking for a workaround that gives a visual indication that an element is "disabled" and also prevents default functionality while still preserving focusability and click events, following is a simplified example where the submit button appears to be disabled and is prevented from "submitting" unless the input contains some text (also restores "disabled" state if input is cleared).

const input = document.querySelector('input');
const button = document.querySelector('button');
input.addEventListener('input', (event) => {
  const target = event.currentTarget;
  const next = target.nextElementSibling;
  if (target.value) {
    next.classList.remove('disabled');
  } else {
    next.classList.add('disabled');
  }
});

button.addEventListener('click', (event) => {
  const target = event.currentTarget;
  if (target.classList.contains('disabled')) {
    event.preventDefault();
    console.log('not submitted');
  } else {
    console.log('submitted');
  }
});
button {
  background-color: #fff;
  color: #0d47a1;
  border: 2px solid #0d47a1;
}

button.disabled {
  background-color: #e0e0e0;
  color: #bdbdbd;
  border: 2px solid #bdbdbd;
  cursor: default;
}
    
button.disabled:focus {
  outline: none;
}
<input type="text">
<button class="disabled">Submit</button>
Fred Gandt
  • 4,217
  • 2
  • 33
  • 41
benvc
  • 14,448
  • 4
  • 33
  • 54
  • 1
    I like it. This is probably the route I'll go. Only modification, I'll probably add `aria-disabled="true"` along with the `disabled` class to improve accessibility. – crenshaw-dev Aug 16 '18 at 01:36
3

You could add an event listener to the keydown event and listen for the tab key like in the code snippet,

document.addEventListener("keydown", keyDown);

function keyDown(e) {
  switch (e.which) {
    case 9:
      var focused = $(document.activeElement);
      var all_inputs = $("input");
      var disabled_inputs = $("input[disabled='disabled']");
      var diff = all_inputs.length - disabled_inputs.length;
      var index = all_inputs.index(focused);
      if (index == diff - 1 && index != -1 && disabled_inputs.length > 0) {
        $(disabled_inputs[0]).removeAttr("disabled").focus();
        e.preventDefault();
      }
      break;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<input type="text" placeholder="this is not disabled!"> <br>
<input type="password" placeholder="this is not either!"> <br>
<input type="button" value="This is!" disabled="disabled"> <br>
<input type="submit" value="This is too!" disabled="disabled">

This will enable the element as you tab onto it. It doesn't effect normal behavior otherwise. I am assuming you don't want to re-disable the element after the focus leaves.

DarthCadeus
  • 372
  • 3
  • 13
  • Thanks for the code! Unfortunately, I'm hoping for a solution that preserves all other aspects of the "disabledness" of the button besides focus-ability. – crenshaw-dev Aug 13 '18 at 13:25
  • Then I suppose you could skip the part about removing the disabled attribute. I cannot test it now because I am away from my computer at the moment. However, it should still focus. If this does not work, try to manually simulate it (i.e. attaching event listeners and then doing percent default, and using css to simulate the shading (I guess you might be overriding the native style already.) however, I do not recommend it. – DarthCadeus Aug 13 '18 at 14:26
  • By the way, if you want it to be focused on solely so that the view will scroll there, then just leave it so and set the scroll, though I am no expert on UI, I think this will achieve the same effect seen by the end user so long as you prevent the default so that it will not scroll somewhere else. – DarthCadeus Aug 13 '18 at 14:28
  • Unfortunately, removing the disabled attribute is [prerequisite to focusing (test)](http://jsfiddle.net/xbLhewa0/). I'm considering the "styled but not actually disabled" route. Manually setting the scroll seems even more intrusive on default behavior than style trickery. – crenshaw-dev Aug 13 '18 at 14:30
  • Yeah I agree on second thought. All kinds of stuff could go wrong. I think if you are dealing with a text input, preventing the o text change event will certainly help. Also, is it possible to disable it, let it focus, and then disable it? I think the focus might just away though, but you could certainly hook a call back on the focus event to disable it once it is focused. – DarthCadeus Aug 13 '18 at 14:34
  • Though this is not directly answering the question, it would be easier if you just hid the next element. And why would you want the user to be able to focus on a disabled element anyway? – DarthCadeus Aug 13 '18 at 14:37
  • No good on the enabled/disable trick [(test)](http://jsfiddle.net/xbLhewa0/3/). Hide which next element? The submit button, or the next focusable element? It's not so much that I want to allow focus, but rather I want to prevent focus from proceeding to the next element (which may cause an unpleasant scroll - see linked test). Maybe I need to handle the tab keydown and prevent default? Not sure of side-effects. – crenshaw-dev Aug 13 '18 at 14:40
  • 1
    That could be it. Normally no one can type a regular tab in browser input fields anyways. Also, I mean the next focusable element, but if that is what you would like to achieve, then preventing the default is enough – DarthCadeus Aug 13 '18 at 14:43
0

It is better if we have some part of the code to understand better your problem.

For this:

I am implementing progressive UI disclosure pattern in my application. Using which I am disabling the next elements. So based on input of one element the next element is enabled.

You must first handle an event for the first element and then in the callback function you need to enable/disable the second element, let say:

For enable:

$('#firstElement).on('click', function(){ $('#secondElement').removeAttr('disabled') })

For disable:

$('#firstElement).on('click', function(){ $('#secondElement').attr('disabled', 'disabled') })

Hope this could help.

Lorenz Meyer
  • 19,166
  • 22
  • 75
  • 121
0

On my idea a input event listener or change event listener for dropdown and input fields work better for your case. E.g:

$(document).on('input','input',function()
{
  $(this).next().prop('disabled',false);
}

or

$(document).on('change','input',function()
{
  $(this).next().prop('disabled',false);
}
0

You can use tabindex attribute in this case. Please refer below code, you need to update tabindex of disabled elements in a way that they get skipped when you press tab.

as per w3schools

The tabindex attribute specifies the tab order of an element (when the "tab" button is used for navigating).

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


    <input class="input-1" tabindex="1" value="1">
    <input class="input-2" tabindex="2" value="2">
    <input type="button" onclick="changeTabIndex();" value="change-tab-index">
    <input class="input-3" tabindex="3" value="3">
    <input class="input-4" tabindex="4" value="4">
    <input class="input-5" tabindex="5" value="5">
    <script type="text/javascript">
     function changeTabIndex() {
      $(".input-5").attr("tabindex",4);
      $(".input-4").attr("tabindex",5);
     }
    </script>
Mayur Chauhan
  • 682
  • 1
  • 12
  • 25