skip to Main Content

I am currently unable to tab into a Select2 enabled <select> element in Firefox (38.0.5) – in other words, cannot access to select <option> in a mouseless manner. In Chrome, you can tab through a form and press enter in order to start selecting an item in the Select2 select element. I have not tested in other browsers, but before submitting an actual bug report I want to verify whether others are experiencing the same issue?

You can duplicate on the demo page.

  • Select2 v4.0.0
  • Twitter Bootstrap 3.3.4 (although have not added any
    additional items to style for Bootstrap)
  • Firefox v38.0.5

4

Answers


  1. This was really bothering me too, so I set it to open on focus. So when tabbing to the select, it will open automatically.

    $(document).ready(function () {
        $(".select2-selection").on("focus", function () {
            $(this).parent().parent().prev().select2("open");
        });
    });
    

    Hope that helps, I’m in a different version of Bootstrap and firefox, so let me know if it doesn’t!

    Login or Signup to reply.
  2. While its not a perfect solution, the following is what we are using to simulate normal keyboard navigation on an HTML form that contains a Select2 element.

    /**
     * WARNING: untested using Select2's option ['selectOnClose'=>true]
     *
     * This code was written because the Select2 widget does not handle
     * tabbing from one form field to another.  The desired behavior is that
     * the user can use [Enter] to select a value from Select2 and [Tab] to move
     * to the next field on the form.
     *
     * The following code moves focus to the next form field when a Select2 'close'
     * event is triggered.  If the next form field is a Select2 widget, the widget
     * is opened automatically.
     *
     * Users that click elsewhere on the document will cause the active Select2
     * widget to close.  To prevent the code from overriding the user's focus choice
     * a flag is added to each element that the users clicks on.  If the flag is
     * active, then the automatic focus script does not happen.
     *
     * To prevent conflicts with multiple Select2 widgets opening at once, a second
     * flag is used to indicate the open status of a Select2 widget.  It was
     * necessary to use a flag instead of reading the class '--open' because using the
     * class '--open' as an indicator flag caused timing/bubbling issues.
     *
     * To simulate a Shift+Tab event, a flag is recorded every time the shift key
     * is pressed.
     */
    jQuery(document).ready(function($) {
        var docBody = $(document.body);
        var shiftPressed = false;
        var clickedOutside = false;
        //var keyPressed = 0;
    
        docBody.on('keydown', function(e) {
            var keyCaptured = (e.keyCode ? e.keyCode : e.which);
            //shiftPressed = keyCaptured == 16 ? true : false;
            if (keyCaptured == 16) { shiftPressed = true; }
        });
        docBody.on('keyup', function(e) {
            var keyCaptured = (e.keyCode ? e.keyCode : e.which);
            //shiftPressed = keyCaptured == 16 ? true : false;
            if (keyCaptured == 16) { shiftPressed = false; }
        });
    
        docBody.on('mousedown', function(e){
            // remove other focused references
            clickedOutside = false;
            // record focus
            if ($(e.target).is('[class*="select2"]')!=true) {
                clickedOutside = true;
            }
        });
    
        docBody.on('select2:opening', function(e) {
            // this element has focus, remove other flags
            clickedOutside = false;
            // flag this Select2 as open
            $(e.target).attr('data-s2open', 1);
        });
        docBody.on('select2:closing', function(e) {
            // remove flag as Select2 is now closed
            $(e.target).removeAttr('data-s2open');
        });
    
        docBody.on('select2:close', function(e) {
            var elSelect = $(e.target);
            elSelect.removeAttr('data-s2open');
            var currentForm = elSelect.closest('form');
            var othersOpen = currentForm.has('[data-s2open]').length;
            if (othersOpen == 0 && clickedOutside==false) {
                /* Find all inputs on the current form that would normally not be focus`able:
                 *  - includes hidden <select> elements whose parents are visible (Select2)
                 *  - EXCLUDES hidden <input>, hidden <button>, and hidden <textarea> elements
                 *  - EXCLUDES disabled inputs
                 *  - EXCLUDES read-only inputs
                 */
                var inputs = currentForm.find(':input:enabled:not([readonly], input:hidden, button:hidden, textarea:hidden)')
                    .not(function () {   // do not include inputs with hidden parents
                        return $(this).parent().is(':hidden');
                    });
                var elFocus = null;
                $.each(inputs, function (index) {
                    var elInput = $(this);
                    if (elInput.attr('id') == elSelect.attr('id')) {
                        if ( shiftPressed) { // Shift+Tab
                            elFocus = inputs.eq(index - 1);
                        } else {
                            elFocus = inputs.eq(index + 1);
                        }
                        return false;
                    }
                });
                if (elFocus !== null) {
                    // automatically move focus to the next field on the form
                    var isSelect2 = elFocus.siblings('.select2').length > 0;
                    if (isSelect2) {
                        elFocus.select2('open');
                    } else {
                        elFocus.focus();
                    }
                }
            }
        });
    
        /**
         * Capture event where the user entered a Select2 control using the keyboard.
         * http://stackoverflow.com/questions/20989458
         * http://stackoverflow.com/questions/1318076
         */
        docBody.on('focus', '.select2', function(e) {
            var elSelect = $(this).siblings('select');
            if (elSelect.is('[disabled]')==false && elSelect.is('[data-s2open]')==false
                && $(this).has('.select2-selection--single').length>0) {
                elSelect.attr('data-s2open', 1);
                elSelect.select2('open');
            }
        });
    
    });
    
    Login or Signup to reply.
  3. Building on zDaniels excellent answer.

    I have created a bower installable version of the code.

    $ bower install select2-tab-fix
    

    Source and documentation at

    https://github.com/peledies/select2-tab-fix

    Login or Signup to reply.
  4. Use @zDaniels Answer, it is working like a charm. But the only problem is it will not close the last select2. To resolve this, you could write a jquery function with the below line in the on-change event of your last select2 element.
    I hope this helps to make a tweak.

        $(document).ready(function () {
          $(YOUR_LAST_ELEMENT).on("change", function () {
            $(this).parent().parent().prev().select2("close");
          });
        });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search