JSFiddle - React, Tailwind, and code Playground
HTML
<div>
<select id="ms" multiple="multiple">
<optgroup label="グループ1を一括選択">
<option value="1">りんご</option>
<option value="2">みかん</option>
<option value="3">桃</option>
</optgroup>
<optgroup label="グループ2を一括選択">
<option value="4">2月</option>
<option value="5">7月</option>
<option value="6">10月</option>
</optgroup>
<optgroup label="グループ3を一括選択">
<option value="7">東京</option>
<option value="8">名古屋</option>
<option value="9">大阪</option>
</optgroup>
<optgroup label="グループ4を一括選択">
<option value="10">IE</option>
<option value="11">Chrome</option>
<option value="12">Firefox</option>
</optgroup>
</select>
</div>
CSS
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
*/
#ms{width:200px;}
.ms-parent {
display: inline-block;
position: relative;
vertical-align: middle;
}
.ms-choice {
display: block;
height: 26px;
padding: 0;
overflow: hidden;
cursor: pointer;
border: 1px solid #aaa;
text-align: left;
white-space: nowrap;
line-height: 26px;
color: #444;
text-decoration: none;
background-color: #fff;
}
.ms-choice.disabled {
background-color: #f4f4f4;
background-image: none;
border: 1px solid #ddd;
cursor: default;
}
.ms-choice > span {
position: absolute;
top: 0;
left: 0;
right: 20px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
padding-left: 8px;
}
.ms-choice > span.placeholder {
color: #999;
}
.ms-choice > div {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 25px;
}
.ms-drop {
overflow: hidden;
display: none;
margin-top: -1px;
padding: 0;
position: absolute;
z-index: 1000;
background: #fff;
color: #000;
border: 1px solid #aaa;
}
.ms-drop.bottom {
top: 100%;
}
.ms-drop.top {
bottom: 100%;
}
.ms-search {
display: inline-block;
margin: 0;
min-height: 26px;
padding: 4px;
position: relative;
white-space: nowrap;
width: 100%;
z-index: 10000;
}
.ms-search input {
width: 100%;
height: auto !important;
min-height: 24px;
padding: 0 20px 0 5px;
margin: 0;
outline: 0;
font-family: sans-serif;
font-size: 1em;
border: 1px solid #aaa;
border-radius: 0;
}
.ms-search, .ms-search input {
-webkit-box-sizing: border-box;
-khtml-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.ms-drop ul {
overflow: auto;
margin: 0;
padding: 5px 8px;
}
.ms-drop ul > li {
list-style: none;
display:...
JavaScript
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* @version 1.0.7
*
* http://wenzhixin.net.cn/p/multiple-select/
*/
(function($) {
'use strict';
function MultipleSelect($el, options) {
var that = this,
elWidth = $el.width();
this.$el = $el.hide();
this.options = options;
this.$parent = $('<div class="ms-parent"></div>');
this.$choice = $('<button type="button" class="ms-choice"><span class="placeholder">' + options.placeholder + '</span><div></div></button>');
this.$drop = $('<div class="ms-drop ' + options.position + '"></div>');
this.$el.after(this.$parent);
this.$parent.append(this.$choice);
this.$parent.append(this.$drop);
if (this.$el.prop('disabled')) {
this.$choice.addClass('disabled');
}
this.$choice.css('width', elWidth + 'px');
this.$drop.css({
width: (options.width || elWidth) + 'px'
});
$('body').click(function(e) {
if ($(e.target)[0] === that.$choice[0] || $(e.target).parents('.ms-choice')[0] === that.$choice[0]) {
return;
}
if (($(e.target)[0] === that.$drop[0] || $(e.target).parents('.ms-drop')[0] !== that.$drop[0]) && that.options.isOpen) {
that.close();
}
});
if (this.options.isOpen) {
this.open();
}
}
MultipleSelect.prototype = {
constructor: MultipleSelect,
init: function() {
var that = this,
html = [];
if (this.options.filter) {
html.push('<div class="ms-search">', '<input type="text" autocomplete="off" autocorrect="off" autocapitilize="off" spellcheck="false">', '</div>');
}
html.push('<ul>');
if (this.options.selectAll && !this.options.single) {
html.push('<li>', '<label>', '<input type="checkbox" name="selectAll" /> ',...