Sofia Lazrak
Sofia Lazrak

Reputation: 314

Custom select box

I am trying to style a select drop down box. The custom select box has rounded corners and a dropdown list (a box that drops down with the options) that shows on focus. I used the css below to style the select box. I have also substituted the html select with DIV elements.

Here is the code I have used so far:

document.querySelector('.custom-select-wrapper').addEventListener('click', function() {
  this.querySelector('.custom-select').classList.toggle('open');
  for (const option of document.querySelectorAll(".custom-option")) {
    option.addEventListener('click', function() {
      if (!this.classList.contains('selected')) {
        this.parentNode.querySelector('.custom-option.selected').classList.remove('selected');
        this.classList.add('selected');
        this.closest('.custom-select').querySelector('.custom-select__trigger span').textContent = this.textContent;
      }
    })
  }
})
.custom-select-wrapper {
  position: relative;
  user-select: none;
  width: 188px;
  z-index: 30000000000;
}

.custom-select {
  position: relative;
  display: flex;
  flex-direction: column;
}

.custom-select__trigger {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  height: 27px;
  background: #ffffff;
  cursor: pointer;
  border: 1px solid #707070;
  border-radius: 8px;
}

.custom-options {
  position: absolute;
  display: block;
  top: 100%;
  left: 0;
  right: 0;
  border: 1px solid #707070;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  background: #fff;
  transition: all 0.5s;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  z-index: 2;
}

.custom-select.open .custom-options {
  opacity: 1;
  visibility: visible;
  pointer-events: all;
}

.custom-option {
  position: relative;
  display: block;
  padding: 0 10px 0 10px;
  line-height: 25px;
  cursor: pointer;
  transition: all 0.5s;
}

.arrow {
  position: relative;
  top: 15px;
  right: 15px;
}

.arrow::before,
.arrow::after {
  content: "\f0d7";
  font-family: "Font Awesome 5 Free";
  font-size: 20px;
  font-weight: 700;
  color: #394a6d;
  position: absolute;
  bottom: 0px;
}
<div class="custom-select-wrapper">
  <div class="custom-select">
    <div class="custom-select__trigger">
      <span>Option 1</span>
      <div class="arrow"></div>
    </div>
    <div class="custom-options">
      <span class="custom-option selected" data-value="tesla">Option 2</span>
      <span class="custom-option" data-value="volvo">Option 3</span>
    </div>
  </div>
</div>

The styles I have applied to the select tag are coming into effect, but the problem is that the dropdown box top border does not blend with the select box itself on focus. Is it only possible to change the SELECT input style on focus from a round border to a square border?

Would someone with some more knowledge in this regard please take a few minutes to suggest a solution?

Upvotes: 0

Views: 1176

Answers (2)

Sofia Lazrak
Sofia Lazrak

Reputation: 314

The above code is a solution strictly from a styling point of view. But as per @CBroe remarks, from a usability point of view (for example using the select via keyboard is impossible), the code is not optimal.

This is why I came up with a solution that uses the jQuery plugin Select2

If anyone is interested here is a link to the code https://www.codeply.com/p/Z999PpuSOK

Upvotes: 0

Terry
Terry

Reputation: 66218

It depends on what you mean by "blending", but if you want to achieve a more harmonious look, you can do the following:

  • Set the border-bottom-left-radius and border-bottom-right-radius of the trigger element to 0px when the dropdown is open, so that the select trigger visually continues to the dropdown that is visible
  • Remove the top border of the dropdown, so that you don't have a doubly-thick border separating the trigger and the dropdown

See proof-of-concept below:

document.querySelector('.custom-select-wrapper').addEventListener('click', function() {
  this.querySelector('.custom-select').classList.toggle('open');
  for (const option of document.querySelectorAll(".custom-option")) {
    option.addEventListener('click', function() {
      if (!this.classList.contains('selected')) {
        this.parentNode.querySelector('.custom-option.selected').classList.remove('selected');
        this.classList.add('selected');
        this.closest('.custom-select').querySelector('.custom-select__trigger span').textContent = this.textContent;
      }
    })
  }
})
.custom-select-wrapper {
  position: relative;
  user-select: none;
  width: 188px;
  z-index: 30000000000;
}

.custom-select {
  position: relative;
  display: flex;
  flex-direction: column;
}

.custom-select__trigger {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  height: 27px;
  background: #ffffff;
  cursor: pointer;
  border: 1px solid #707070;
  border-radius: 8px;
  transition: all 0.5s;
}

.custom-options {
  position: absolute;
  display: block;
  top: 100%;
  left: 0;
  right: 0;
  border: 1px solid #707070;
  border-top: none;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  background: #fff;
  transition: all 0.5s;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  z-index: 2;
}

.custom-select.open .custom-select__trigger {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.custom-select.open .custom-options {
  opacity: 1;
  visibility: visible;
  pointer-events: all;
}

.custom-option {
  position: relative;
  display: block;
  padding: 0 10px 0 10px;
  line-height: 25px;
  cursor: pointer;
  transition: all 0.5s;
}

.arrow {
  position: relative;
  top: 15px;
  right: 15px;
}

.arrow::before,
.arrow::after {
  content: "\f0d7";
  font-family: "Font Awesome 5 Free";
  font-size: 20px;
  font-weight: 700;
  color: #394a6d;
  position: absolute;
  bottom: 0px;
}
<div class="custom-select-wrapper">
  <div class="custom-select">
    <div class="custom-select__trigger">
      <span>Option 1</span>
      <div class="arrow"></div>
    </div>
    <div class="custom-options">
      <span class="custom-option selected" data-value="tesla">Option 2</span>
      <span class="custom-option" data-value="volvo">Option 3</span>
    </div>
  </div>
</div>

Upvotes: 1

Related Questions