control <select> using separate <ul>

In this example below you will see how to do a control <select> using separate <ul> with some HTML / CSS and Javascript

A boilerplate for controlling a -input with a TODO: - no-js fallback - a11y: tabbing, aria etc

Thumbnail
This awesome code was written by vincentorback, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright vincentorback ©
  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>control <select> using separate <ul></title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <h1>Boilerplate for controlling a &lt;select&gt;-input with a &lt;ul&gt;-list.</h1>

<div class="Select js-select">
  <select class="js-selectControl">
    <option value="apple">Apple</option>
    <option value="banana">Banana</option>
    <option value="kiwi" selected>Kiwi</option>
    <option value="orange" disabled>Orange</option>
    <option value="pineapple">Pineapple</option>
  </select>
</div>
  
  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/vincentorback/control-andltselectandgt-using-separate-andltulandgt-WoKxwv */
.Select {
  margin: 50px;
}

.Select-list {
  
}

.Select-listItem {
  cursor: pointer;
}

.Select-listItem.is-active {
  color: red;
}

.Select-listItem[data-disabled="true"] {
  opacity: .6;
  pointer-events: none;
}



/* Use to hide the <select> element */

.u-hiddenVisually {
  border: 0;
  clip: rect(1px, 1px, 1px, 1px);
  height: 1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}

/*Downloaded from https://www.codeseek.co/vincentorback/control-andltselectandgt-using-separate-andltulandgt-WoKxwv */
var selectEl = document.querySelector('.js-select');
var selectControlEl = selectEl.querySelector('.js-selectControl');

var selectListEl = void 0;
var selectListItems = void 0;

var selectListClass = 'Select-list';
var selectListItemClass = 'Select-listItem';
var activeClass = 'is-active';

/* Set active item */
function setActiveItem(value) {
  var activeControlItem = selectControlEl.options[selectControlEl.options.selectedIndex];
  value = value || activeControlItem.value;

  /* Remove active states from all list elements */
  if (activeControlItem) {
    activeControlItem.removeAttribute('selected');
  }

  Array.from(selectListItems).forEach(function (itemEl) {
    itemEl.classList.remove(activeClass);
  });

  /* Set active states */
  var activeListItem = selectListEl.querySelector('li[data-value="' + value + '"]');
  if (activeListItem) {
    activeListItem.classList.add(activeClass);
    selectControlEl.value = value;
    selectControlEl.querySelector('option[value="' + value + '"]').setAttribute('selected', true);
  }
}

/* Create a <ul>-list from <select>-element */
function createList() {
  selectListEl = stringToElements('<ul class="' + selectListClass + '"></ul>');

  Array.from(selectControlEl.options).forEach(function (option) {
    selectListEl.appendChild(stringToElements('<li\n        class="' + selectListItemClass + '"\n        data-value="' + option.value + '"\n        data-disabled="' + option.disabled + '"\n        tabindex="' + (option.disabled ? -1 : 0) + '"\n        >\n        ' + option.innerHTML + '\n      </li>'));
  });

  selectEl.appendChild(selectListEl);

  selectListItems = selectEl.querySelectorAll('li');

  setActiveItem();

  /* Listen for click on <ul>-items */
  Array.from(selectListItems).forEach(function (itemEl) {
    itemEl.addEventListener('click', function (e) {
      var targetEl = e.currentTarget || e.target;
      setActiveItem(targetEl.getAttribute('data-value'));
    }, false);
    itemEl.addEventListener('keydown', function (e) {
      if (e.keyCode === 13) {
        setActiveItem(e.target.getAttribute('data-value'));
      }
    }, false);
  });

  /* Listen for change in <select> */
  selectControlEl.addEventListener('change', function (e) {
    setActiveItem(e.currentTarget.value);
  });
}

/* Create list on load */
createList();

/* Helper function to create element from string */
function stringToElements(string) {
  var div = document.createElement('div');
  div.innerHTML = string;

  if (div.childNodes.length > 1) {
    return div.childNodes;
  }

  return div.firstChild;
}

Comments