JSFiddle - React, Tailwind, and code Playground
by Michael Prosser
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<select multiple id="userlist">
<option data-value="kevin bagley" value="1005479">Kevin Bagley</option>
<option data-value="doe bill" value="1005172">Doe Bill</option>
<option data-value="frank byers" value="2">Frank Byers</option>
<option data-value="glenn dickey" value="1565">Glenn Dickey</option>
<option data-value="angie fjeldheim" value="1005602">Angie Fjeldheim</option>
<option data-value="mimi lam" value="1005413">Mimi Lam</option>
<option data-value="mike law" value="1000064">Mike Law</option>
<option data-value="nick mitchell" value="1005220">Nick Mitchell</option>
<option data-value="scott rysdon" value="1826">Scott Rysdon</option>
<option data-value="laura schmidt" value="1005557">Laura Schmidt</option>
<option data-value="john sewell" value="1005618">John Sewell</option>
<option data-value="scott sorrows" value="1005501">Scott Sorrows</option>
</select>
CSS
body {
font-family: helvetica, serif;
font-size: 13px;
}
select {
width: 232px;
padding: 6px;
border-radius: 5px;
border: solid 1px #999;
font-size: 12px;
height: 200px;
}
select[multiple] option {
background-color: #fff;
color: #000;
background-image: none;
background-repeat: no-repeat;
padding: 6px;
padding-left: 25px;
background-size: auto 60%;
background-position: 5px 5px;
border-bottom: solid 1px #ebebeb;
transition: all 0.4s;
}
select[multiple] option:checked {
background-color: #e7f9e1 !important;
background-image: url(https://agrisphere-portal.com/live/images/success_small.png);
}
select.selection-segregation.disable-events {
pointer-events: none;
overflow: hidden;
}
select[multiple].selection-segregation option.move-hide {
height: 10px;
opacity: 0.2;
}
select.selection-segregation>optgroup.selected-options-group:empty {
display: none;
}
select.selection-segregation>optgroup>option:first-child {
margin-top: 5px;
}
select.selection-segregation>optgroup>option:last-child {
margin-bottom: 5px;
}
JavaScript
function enableSelectionSegregation(targetElements,availableLabel,selectedLabel){
targetElements.each(function(){
var outputElement = $(this);
outputElement.addClass('selection-segregation');
outputElement.addClass('disabled-events');
outputElement.html('<optgroup label="' + availableLabel + '">' + outputElement.html() + '</optgroup>');
outputElement.prepend('<optgroup label="' + selectedLabel + '" class="selected-options-group"></optgroup>');
// index caching
outputElement.find('option').each(function(index) {
$(this).attr('data-selection-index', index);
});
outputElement.find('option').mousedown(function(e) {
e.preventDefault();
var scroll = outputElement.scrollTop();
var cached_this = $(this);
outputElement.addClass('disable-events');
cached_this.prop('selected', !cached_this.prop('selected'));
cached_this.addClass('move-hide');
setTimeout(function() {
if (cached_this.prop('selected')) {
var detached = cached_this.detach();
var eq = parseInt(cached_this.attr('data-selection-index'));
var appended = false;
// check if the current selections are all higher indexes than new selection
var greater = true;
outputElement.find('optgroup[label="' + selectedLabel + '"]>option').each(function() {
var itemIndex = parseInt($(this).attr('data-selection-index'));
if (itemIndex < eq) {
greater = false;
}
});
if (outputElement.find('optgroup[label="' + selectedLabel + '"]>option').length == 0) {
outputElement.find('optgroup[label="' + selectedLabel + '"]').prepend(detached);
appended = true;
} else if (greater) {
outputElement.find('optgroup[label="' + selectedLabel + '"]').prepend(detached);
appended = true;
} else {
...