Selectonic is jQuery based plugin for making any list of items selectable by mouse and keyboard.

Download minified Download development

See docs and source on GitHub

For what

Selectonic helps to implement widgets with ability to select items. It could be usefull in webapp where are different widgets like menus, dropdowns with keyboard input, lists of items with actions and more. See examples below.

  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
  • Item 6
  • Item 7
  • Item 8
  • Item 9
  • Item 10
  • Item 11
  • Item 12
  • Item 13
  • Item 14
  • Item 15
  • Item 16
  • Item 17
  • Item 18
  • Item 19
  • Item 20

Exapmle: List with actions

Lets see simple list of items with actions buttons. Try to select items with mouse or keyboard then click action button. The list has multiple selection

(function( $ ) {
  'use strict';

  var $el = $('#actions-list'),
  actions = $el.find('.actions-list__actionbar'),
  list    = $el.find('.actions-list__group');

  // Attach selectonic plugin
  list.selectonic({
    multi: true,
    keyboard: true,
    focusBlur: true,
    selectionBlur: true,

    // Before any changes
    before: function(e) {
      if (e.target === actions[0] || $(e.target).is('button.actions-list__button')) {
        this.selectonic('cancel');
      }
    },

    // When one or more items selectes
    select: function() {
      toggleActions(false);
    },

    // When all items clears selection
    unselectAll: function() {
      toggleActions(true);
    }
  });

  actions.on('click', 'button', function(event) {
    event.preventDefault();
    // Get selected items from the list
    // and pass them to a method
    doAction( list.selectonic('getSelected') );
    this.blur();
  });

  function toggleActions (state) {
    if (state === void 0) {
      actions.toggleClass('disabled');
    } else {
      actions.toggleClass( 'disabled', state );
    }
  }

  function doAction (items) {
    items.each(function(index, el) {
      var $el = $(el);
      $el.addClass('animate');
      setTimeout(function() {
        $el.removeClass('animate');
      }, 300);
    });
  }

  toggleActions(true);

})( jQuery );

It supports keys: Up, Down, PageUp, PageDown and HOME, END.

You could focus it by TAB, press arrow and choose item.

  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
  • Item 6
  • Item 7
  • Item 8
  • Item 9
  • Item 10
  • Item 11
  • Item 12
  • Item 13
  • Item 14
  • Item 15
  • Item 16
  • Item 17
  • Item 18
  • Item 19
  • Item 20

Example: Select input

There are many implementations of select input, but almost all with same flaw — lack of keyboard support. Selectonic has all necessary logic for it. This example of select input demonstrates that.

(function( $, window ) {
  'use strict';

  var keyCode = { UP:38, DOWN:40, ESCAPE:27, ENTER:13, SPACE:32 },

  Select = function( elem ) {
    this.$el     = $( elem );
    this.button  = this.$el.find('.select-trigger');
    this.title   = this.button.find('.select-title');
    this.list    = this.$el.find('.select-group');
    this.isOpend = false;
    this.isEnabled = true;
    this.init();
  };


  Select.prototype.init = function() {
    var _this = this;

    this.button.on('blur', function( e ) {
      if ( !_this.isEnabled ) { return; }
      _this.close.call( _this, e );
    })
    .on('mouseup', function(e) {
      e.stopPropagation();
    });

    this.$el
      .on('keydown', function( e ) {
        if ( !_this.isEnabled ) { return; }
        _this.keyHandler.call( _this, e );
      })
      .on('mousedown', function(e) {
        if ( !_this.isEnabled ) { return; }
        var isOnButton = _this.button[0] === e.target ||
          _this.title[0] === e.target;

        if ( isOnButton ) {
          if (!_this.isOpend) {
            e.stopPropagation();
            _this.open.call( _this );
          } else {
            _this.close.call( _this );
          }
          return;
        }
        e.preventDefault();
      });


    // attach selectionc with options
    this.list.selectonic({
      multi: false,
      keyboard: true,
      keyboardMode: 'toggle',
      mouseMode: 'mouseup',
      focusOnHover: true,
      selectionBlur: false,
      focusBlur: true,

      // After plugin's initialisation
      create: function() {
        // we don't want to list reaction on keyboard in closed state
        this.selectonic('disable');
      },
      // When item of list has been selected
      select: function( e, ui ) {
        e.preventDefault();
        _this.selected = ui.target;
        _this.setValue( ui.items.html() );
        _this.close();
      },
      // After each works cycle
      stop: function( e, ui ) {
        e.preventDefault();
        if ( (e.which === keyCode.ENTER && _this.isOpend) || !ui.target ) {
          _this.close();
        }
      }
    });
  };


  Select.prototype.keyHandler = function( e ) {
    var key = e.which;
    if ( !this.isOpend &&
      (key === keyCode.UP || key === keyCode.DOWN || key === keyCode.SPACE )
    ) {
      e.stopPropagation();
      e.preventDefault();
      this.open();
    }
    if ( this.isOpend && key === keyCode.ESCAPE ) {
      this.close();
      e.stopPropagation();
    }
  };


  Select.prototype.open = function() {
    this.$el.addClass('opend');
    // Enable selectonic on the list
    this.list.selectonic('enable');

    if ( this.selected ) {
      this.list
        // Set focus on selected element
        .selectonic('focus', this.selected)
        // and scroll to it
        .selectonic('scroll');
    }
    this.isOpend = true;
  };


  Select.prototype.close = function() {
    this.$el.removeClass('opend');
    // Disable plugin on the list
    this.list.selectonic('disable');
    this.isOpend = false;
  };


  Select.prototype.setValue = function( val ) {
    this.title.html( val );
  };


  Select.prototype.disable = function() {
    if ( this.isOpend ) { this.close(); }
    this.list.selectonic('disable');
    this.isEnabled = false;
    this.$el.addClass('disabled');
  };


  Select.prototype.enable = function() {
    if ( this.isOpend ) { this.list.selectonic('enable'); }
    this.isEnabled = true;
    this.$el.removeClass('disabled');
  };


  $.fn.mySelect = function( options ) {
    if (!this.length) { return this; }
    var obj;
    if ( options && typeof options === 'string' ) {
      obj = this.data('plugin_select');
      obj[options].call( obj );
    } else {
      this.each(function() {
        var $this = $(this);
        obj = new Select(this);
        $this.data('plugin_select', obj);
      });
    }
    return $(this);
  };

})( jQuery, window );
  • handleItem 1
  • handleItem 2
  • handleItem 3
  • handleItem 4
  • handleItem 5
  • handleItem 6
  • handleItem 7
  • handleItem 8
  • handleItem 9
  • handleItem 10
  • handleItem 11
  • handleItem 12
  • handleItem 13
  • handleItem 14
  • handleItem 15
  • handleItem 16
  • handleItem 17
  • handleItem 18
  • handleItem 19
  • handleItem 20

Sandbox

Try to play with options and methods. For all possible options and methods see docs on GitHub.

Options

mouseMode
keyboardMode

See all options in the docs.

Methods

select/unselect

You can select/unselect items by plugin interface. Plugin accept selector or element:

elem.selectonic('select', someElements);

elem.selectonic('select', ":even");

elem.selectonic('select', "li:eq(3)");

See all methods in the docs.

About

Requires jQuery 1.7+
Tested in Firefox, Chrome, Safari, Opera, IE8+

Author: Alexey Novichkov

License: Released under the MIT License. Feel free to use it in personal and commercial projects.