JSFiddle - React, Tailwind, and code Playground
HTML
<select>
<option selected="selected">option 1</option>
<option>option 2</option>
<option>option 3</option>
</select>
<select size="4">
<option selected="selected">option 1</option>
<option>option 2</option>
<option>option 3</option>
<option>option 4</option>
<option>option 5</option>
<option>option 6</option>
</select>
<select multiple="multiple">
<option selected="selected">option 1</option>
<option>option 2</option>
<option>option 3</option>
<option>option 4</option>
<option>option 5</option>
<option>option 6</option>
</select>
CSS
select:focus {
border: 1px solid red;
}
JavaScript
var selects = document.getElementsByTagName('select');
for (var i = 0; i < selects.length; i++) {
selects[i].addEventListener('keydown', function (event) {
var activeElement = this;
switch (event.which || event.keyCode || event.charCode) {
case 37:
// left arrow
while (activeElement = activeElement.previousSibling) {
if (activeElement.nodeType === 1) break;
}
event.preventDefault();
ensurePreventDefault(this);
break;
case 39:
// right arrow
while (activeElement = activeElement.nextSibling) {
if (activeElement.nodeType === 1) break;
}
event.preventDefault();
ensurePreventDefault(this);
break;
}
if (activeElement && activeElement !== this) {
activeElement.focus();
}
});
}
function ensurePreventDefault(select) {
var selectedIndex, scrollTop;
function saveState() {
selectedIndex = select.selectedIndex;
scrollTop = select.scrollTop;
}
saveState();
if (!select.multiple && !select.size) {
select.addEventListener('change', saveState);
}
// use setTimeout to wait a frame and see if the selected index was changed
setTimeout(function () {
select.removeEventListener('change', saveState);
if (select.selectedIndex !== selectedIndex) {
console.log('Damn you, Firefox!');
select.selectedIndex = selectedIndex;
select.scrollTop = scrollTop;
}
});
}