selectmenu

by Kim Ara

HTML

<!-- 1 -->
<selectmenu class="my-custom-select1">
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</selectmenu>

<!-- 2 -->
<selectmenu class="my-custom-select2">
  <div slot="button">
    <button behavior="button">Open</button>
    <span class="label">Choose an option</span>
  </div>
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</selectmenu>

<!-- 3 -->
<selectmenu class="my-custom-select3">
  <div slot="listbox">
    <div popup behavior="listbox">
      <option>Option 1</option>
      <option>Option 2</option>
      <option>Option 3</option>
      <option>Option 4</option>
      <option>Option 5</option>
    </div>
  </div>
</selectmenu>

<!-- 4 -->
<selectmenu class="my-custom-select4">
  <div slot="button">
    <span class="label">Choose a plant</span>
    <span behavior="selected-value" slot="selected-value"></span>
    <button behavior="button"></button>
  </div>
  <div slot="listbox">
    <div popup behavior="listbox">
      <div class="section">
        <h3>Flowers</h3>
        <option>Rose</option>
        <option>Lily</option>
        <option>Orchid</option>
        <option>Tulip</option>
      </div>
      <div class="section">
        <h3>Trees</h3>
        <option>Weeping willow</option>
        <option>Dragon tree</option>
        <option>Giant sequoia</option>
      </div>
    </div>
  </div>
</selectmenu>



<selectmenu class="multiselect">
      <div slot="button" behavior="button">
        <ul class="selected-values"><li><span class="label">Black olives</span><span class="remove"><svg viewBox="64 64 896 896" focusable="false" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5...

CSS

selectmenu {
  display: block;
  max-width: 300px;
}

/* 1 */
.my-custom-select1::part(button) {
  color: white;
  background-color: #f00;
  padding: 5px;
  border-radius: 5px;
}

.my-custom-select1::part(listbox) {
  padding: 10px;
  margin-top: 5px;
  border: 1px solid red;
  border-radius: 5px;
}

/* 2 */
.my-custom-select2 [slot='button'] {
  display: flex;
  align-content: center;
}
.my-custom-select2 button {
  padding: 5px;
  border: none;
  background: #f06;
  border-radius: 5px 0 0 5px;
  color: white;
  font-weight: bold;
}
.my-custom-select2 .label {
  padding: 5px;
  border: 1px solid #f06;
  border-radius: 0 5px 5px 0;
}

/* 3 */
.my-custom-select3 [popup] {
  width: 300px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  gap: 10px;
  padding: 10px;
  box-shadow: none;
  margin: 10px 0;
  border: 1px solid;
  background: #f7f7f7;
}

/* 4 */
.my-custom-select4 [slot='button'] {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.my-custom-select4 button {
  border: none;
  margin: 0;
  padding: 0;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: grid;
  place-content: center;
}
.my-custom-select4 button::before {
  content: '\25BC';
}
.my-custom-select4 [popup] {
  padding: 0;
}
.my-custom-select4 .section {
  padding: 1rem 0 0;
  background: radial-gradient(ellipse 60% 50px at center top, #000a 0%, transparent 130%);
}
.my-custom-select4 h3 {
  margin: 0 0 1rem 0;
  text-align: center;
  color: white;
}
.my-custom-select4 option {
  text-align: center;
  padding: 0.5rem;
}






      .multiselect [slot="button"] {
        background-color: rgb(255, 255, 255);
        border-width: 1px;
        border-style: solid;
        border-color: rgb(217, 217, 217);
        border-radius: 2px;
        transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;
        width: 300px;
        min-height: 32px;
      }
      
      .multiselect:focus-within [slot="button"] {
        box-shadow: 0 0 0 2px...

JavaScript

const multiselect = document.querySelector('.multiselect');
      const multiSelectedValuesContainer = multiselect.querySelector('.selected-values');
      let multiValues = [];

      multiselect.addEventListener('click', e => {
        const option = e.target.closest('option');
        if (!option) return;

        const newValue = option.value;
        if (multiValues.includes(newValue)) {
          multiRemove(newValue);
        } else {
          multiAdd(newValue);
        }
      });

      multiselect.addEventListener('click', e => {
        const removeIcon = e.target.closest('.remove');
        const selectedValue = e.target.closest('.selected-values li');
        if (!removeIcon) return;

        e.stopPropagation();

        multiRemove(selectedValue.textContent);
      }, true);

      function multiAdd(value) {
        multiValues.push(value);

        multiRefreshSelectedValues();
        multiRefreshOptions();
      }

      function multiRemove(toRemove) {
        multiValues = multiValues.filter(value => value !== toRemove);

        multiRefreshSelectedValues();
        multiRefreshOptions();
      }

      function multiRefreshSelectedValues() {
        multiSelectedValuesContainer.innerHTML = '';

        multiValues.forEach(value => {
          const label = document.createElement('span');
          label.classList.add('label');
          label.textContent = value;

          const remove = document.createElement('span');
          remove.classList.add('remove');
          remove.innerHTML = '<svg viewBox="64 64 896 896" focusable="false" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8...