JSFiddle - React, Tailwind, and code Playground

by Dogbert

HTML

<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<div id="first" class="row"></div>
<div id="second" class="row"></div>

<template id="dual-list-template">
  <div class="dual-list list-left col-md-5">
    <div class="well text-right">
      <div class="row">
        <div class="col-md-10">
          <div class="input-group">
            <span class="input-group-addon glyphicon glyphicon-search"></span>
            <input type="text" name="search" class="form-control" placeholder="search" />
          </div>
        </div>
        <div class="col-md-2">
          <div class="btn-group">
            <a class="btn btn-default selector" title="select all"><i class="glyphicon glyphicon-unchecked"></i></a>
          </div>
        </div>
      </div>
      <ul class="list-group">
      </ul>
    </div>
  </div>

  <div class="list-arrows col-md-1 text-center">
    <button class="btn btn-default btn-sm move-left">
      <span class="glyphicon glyphicon-chevron-left"></span>
    </button>

    <button class="btn btn-default btn-sm move-right">
      <span class="glyphicon glyphicon-chevron-right"></span>
    </button>
  </div>

  <div class="dual-list list-right col-md-5">
    <div class="well">
      <div class="row">
        <div class="col-md-2">
          <div class="btn-group">
            <a class="btn btn-default selector" title="select all"><i class="glyphicon glyphicon-unchecked"></i></a>
          </div>
        </div>
        <div class="col-md-10">
          <div class="input-group">
            <input type="text" name="search" class="form-control" placeholder="search" />
            <span class="input-group-addon glyphicon glyphicon-search"></span>
          </div>
        </div>
      </div>
      <ul class="list-group">
      </ul>
    </div>
  </div>
</template>

CSS

.dual-list .list-group {
          margin-top: 8px;
        }
        
        .list-left li,
        .list-right li {
          cursor: pointer;
        }
        
        .list-arrows {
          padding-top: 100px;
        }
        
        .list-arrows button {
          margin-bottom: 20px;
        }

JavaScript

var DualList = {
  init: function(options) {
    var $el = $(this);
    $el.html($("#dual-list-template").html());

    $el.on('click', '.move-left', function() {
      $el.find('.list-right ul li.active').appendTo($el.find('.list-left ul'));
    });
    $el.on('click', '.move-right', function() {
      $el.find('.list-left ul li.active').appendTo($el.find('.list-right ul'));
    });

    $el.on('input', '[name=search]', function() {
      var $lis = $(this).closest('.dual-list').find('li');
      var text = $(this).val().toLowerCase();
      $lis.hide().filter(function() {
        return $(this).text().indexOf(text) >= 0;
      }).show();
    });

    $el.on('click', '.list-group-item', function() {
      $(this).toggleClass('active');
    });
    
    return $el;
  },
  addToLeft: function(htmls) {
  var $this = $(this);
    if (!$.isArray(htmls)) {
      htmls = [htmls];
    }
    htmls.forEach(function(html) {
      $this.find('.list-left ul').append($('<li>').addClass('list-group-item').html(html));
    });
    return $this;
  },
  addToRight: function(htmls) {
    var $this = $(this);
    if (!$.isArray(htmls)) {
      htmls = [htmls];
    }
    htmls.forEach(function(html) {
      $this.find('.list-right ul').append($('<li>').addClass('list-group-item').html(html));
    });
    return $this;
  }
}

$.fn.dualList = function(arg1, arg2) {
  if (DualList[arg1]) {
    return DualList[arg1].call(this, arg2);
  } else {
    return DualList.init.call(this, arg1);
  }
}

var items = 'lorem ipsum dolor sit amet'.split(' ');
console.log(items);
$("#first").dualList().dualList('addToLeft', items).dualList('addToRight', ['foo', 'bar']);
$("#second").dualList().dualList('addToRight', items);