27

I made a form control which uses as its container (see the Yes/No toggler below)

toggle example
Here's the code for that:

<span class="toggle">
    <i>Yes</i>
    <i>No</i>
    <input type="hidden" name="toggle-value" value="0">
</span>

My CSS isn't relevant to the question, but it's included for comprehension of my control:

.toggle { width:auto; height: 20px; display: inline-block; position: relative;  cursor: pointer; vertical-align: middle; padding: 0; margin-right: 27px; color: white !important;}
.toggle i { display: block; padding: 0 12px; width: 100%; height: 100%; -webkit-border-radius: 12px; -moz-border-radius: 12px; border-radius: 12px; text-align: center; font: 11px/20px Arial !important; text-transform: uppercase; }
.toggle i:first-child { -moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) inset; box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5) inset; background-color: #73B9FF; }
.toggle i:last-child { -moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) inset; box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5) inset; background-color: #cc0000; position: relative; top: -20px; z-index: -1; }
.toggle.on i:first-child { z-index: 1; } /* they overlap but on click they switch who gets to be on top. */
.toggle.on i:last-child { z-index: -1; }  
.toggle.off i:first-child { z-index: -1; }
.toggle.off i:last-child { z-index: 1; }
.toggle.off i:last-child:before { content: " "; display:block; position:absolute; left:1px; top:1px; text-indent: -9999px; width: 18px; height: 18px; -webkit-border-radius: 11px; -moz-border-radius: 11px; border-radius: 11px; z-index: 1;  background-color: #fff; } /* circle */
.toggle.on i:first-child:after { content: " "; display:block; position:absolute; right:-23px; top:1px; text-indent: -9999px; width: 18px; height: 18px; -webkit-border-radius: 11px; -moz-border-radius: 11px; border-radius: 11px; z-index: 1;  background-color: #fff; } /* circle */

and the JS that makes it all work:

.on('click', '.toggle', function(){
    var input = $(this).next('input');
        if(input.val() == 1) {
            $(this).removeClass('on').addClass('off');
            input.val(0).change();
        } else {
            $(this).removeClass('off').addClass('on');
            input.val(1).change();
        }
}

The problem is that I'm using this all over my application for data-entry. Have you ever wanted to NOT use the mouse when you're entering a lot of data? Yeah, me too. So you hit TAB and a toggle like this should respond to the spacebar. But instead, since it's just a element, it is skipped altogether.

I'm hoping someone can help me solve the question of "how the heck do I make this a tab stop AND be in the correct order"?

============== EDIT: HERE IS MY UPDATED JQUERY CODE CONTAINING THE SOLUTION:

$('.toggle').click(function(){
    var input = $(this).next('input');
        if(input.val() == 1) {
            $(this).removeClass('on').addClass('off');
            input.val(0).change();
        } else {
            $(this).removeClass('off').addClass('on');
            input.val(1).change();
        }
}).focus(function() {
    $(this).bind('keydown', 'space', function(e){
        $(this).trigger('click')
        e.preventDefault();
    });

}).blur(function() {
    $(this).unbind('keydown');

}).attr('tabIndex', 0);
mydoglixu
  • 934
  • 1
  • 7
  • 25

2 Answers2

40

Try setting your tabindex to 0, on the non-anchor elements you would like to make "tabbable". For example tabindex="0". This way, you won't mess with the tabbing order, or have to throw tabindexs all over the place.

bruh
  • 2,205
  • 7
  • 30
  • 42
  • 3
    just as another little note on this, because the control is using SPACE, I needed to prevent the browser from scrolling down, so I added the preventDefault() function to it. – mydoglixu Oct 02 '14 at 12:51
  • Note that you need to catch the key event (spacebar) on the `span` element to make it react as you want. – Avatar Jan 25 '21 at 23:14
2

Look into the html attribute tabindex. Basically you should be able to set tabindex on each input you want to focusable via the tab key. Start the first one a 1 and just count upwards for each input. If you also want to take an input out of focusing via the tab key set the tabindex to -1.

Adam Merrifield
  • 10,307
  • 4
  • 41
  • 58
  • 1
    This is the only way I know so far, but the problem I am running into is that none of the other form controls have tabindex set explicitly, so when I set my it's all out of order. Plus, I'm trying to do this in the toggle object itself so that it need not rely on manually setting tabindex on every other form control- this is a BIG database site and that would be a nightmare – mydoglixu Oct 02 '14 at 03:57
  • @mydoglixu Correct, my suggest is to set *all* of the input's `tabindex`s. – Adam Merrifield Oct 02 '14 at 03:58
  • I edited my comment above to address that- it has to be set somehow by the toggle control only, it's not possible to go back and set all of the inputs like that – mydoglixu Oct 02 '14 at 03:59
  • @mydoglixu in that case, I would recommend instead of using a span + a hidden input field, use a radio button styled. This way it will only tab over 1 of them per name. [demo](http://jsfiddle.net/tocghw8h/) – Adam Merrifield Oct 02 '14 at 04:06