JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://rawgit.com/GusGarsaky/HelperJS/master/helper.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<drop-down class="dropdown">
<span>Dropdown menu<i class="fa fa-cog"></i></span>
<ul>
<li><a href="#">Github<i class="fa fa-github"></i></a></li>
<li><a href="#">BitBucket<i class="fa fa-bitbucket"></i></a></li>
<li><a href="#">Dropbox<i class="fa fa-dropbox"></i></a></li>
<li><a href="#">Google drive<i class="fa fa-google"></i></a></li>
</ul>
</drop-down>
CSS
* {
margin: 0px;
padding: 0px;
}
body {
background-color: #2d2d2d;
display: flex;
justify-content: center;
padding: .75rem;
}
/* SELECT
===================================*/
.dropdown {
background-color: #e9e9e9;
border: 1px solid #d2c2c2;
border-radius: 2px;
display: flex;
flex-flow: column nowrap;
height: 40px;
justify-content: center;
position: relative;
width: 160px;
}
.dropdown:hover { cursor: pointer; }
.dropdown > span {
align-items: center;
color: #555;
display: flex;
font-family: 'segoe ui';
font-size: .9rem;
justify-content: space-between;
padding: 0px .75rem;
pointer-events: none;
}
.dropdown > span > i {
color: inherit;
}
.dropdown ul {
background-color: #e9e9e9;
border: 1px solid #d2c2c2;
border-radius: 2px;
box-shadow: 0px 2px 5px 0px rgba(0,0,0,.5);
display: block;
list-style: none;
padding: .5rem 0;
position: absolute;
opacity: 0;
pointer-events: none;
visibility: hidden;
top: 160%;
transition: all .2s ease-out;
width: 100%;
z-index: 999;
}
.dropdown ul > li {
color: #555;
display: block;
}
.dropdown ul > li:hover {
background-color: #007095;
color: rgba(255,255,255,.9);
}
.dropdown ul > li > a {
align-items: center;
color: inherit;
display: flex;
font-family: 'segoe ui';
font-size: .9rem;
justify-content: space-between;
padding: .5rem .75rem;
text-decoration: none;
}
.dropdown ul > li > a > i {
color: inherit;
}
.dropdown:focus {
outline: none;
}
.dropdown-active > ul {
pointer-events: auto;
opacity: 1;
top: 140%;
visibility: visible;
}
JavaScript
const helper = new Helper();
/* SELECT
============================================================*/
var ddProto = Object.create(HTMLElement.prototype);
ddProto.properties = {
list: null,
options: null,
value: null,
icon: null,
index: -1,
};
ddProto.initEvents = function() {
var self = this;
// mouse over button
this.addEventListener('mouseover', function(e) {
if(!helper.hasClass(this, 'dropdown-active'))
helper.addClass(this, 'dropdown-active');
});
// mouseleave over button
this.addEventListener('mouseleave', function(e){
var rect = this.getBoundingClientRect();
var left = e.pageX;
var bottom = e.pageY;
// if mouse is out of X axis of button and if mouse is
// out (only of top) of Y axis of button, hide ul
if(left < rect.left || left >= rect.right || bottom < rect.top) {
helper.delClass(this, 'dropdown-active');
}
});
// list loses hover
this.properties.list.addEventListener('mouseleave', function(e) {
if(helper.hasClass(self, 'dropdown-active'))
helper.delClass(self, 'dropdown-active');
});
// elements click
[].forEach.call(this.properties.options, function(e) {
e.addEventListener('click', function(event){
event.preventDefault();
// set the text of selected value to button
helper.text(self.properties.value, e.innerText);
// set the position of selected value
self.properties.index = helper.position(e.parentNode);
// set the <i> class name to the button (fontawesome)
self.properties.icon.className = this.children[0].className;
// hide ul
helper.delClass(self,'dropdown-active');
},true);
});
};
ddProto.value = function() {
return this.properties.value;
};
ddProto.index = function() {
return this.properties.index;
}
ddProto.createdCallback = function() {
this.properties.list = this.querySelector('ul');
this.properties.options = this.querySelectorAll('ul > li > a');
this.properties.value = this.querySelector('span');
this.properties.icon = this.querySelector('span >...