0

I have a custom select list which I did with checkbox and label elements. Then I added a little JS script that changes options on click. It works perfectly, except you can't close it on click outside of it or its child elements. I tried to use event listener(commented in snippet) to track if the click was done outside and if it is - change checkbox status on 'false' and it kinda worked, however, it breaks the original checkbox functionality and you can't now close it in any way except for clicking outside of it. Is there a way I can fix this?

//SELECT FROM LIST
function selectList(id) {
    let selected = document.getElementById('selected');
  selected.innerHTML = id;
}

//BREAKS CHECKBOX
//window.addEventListener('mouseup', function(event){
//  let checkbox = document.getElementById('checkbox');
//  if (event.target != checkbox && event.target.parentNode != checkbox){
//    checkbox.checked = false;
//  }
// });
.btn {
  display: block;
  width: 100px;
  height: 50px;
  text-align: center;
  color: white;
  background: black;
  border-radius: 15px;
  line-height: 50px;
  cursor: pointer;
  user-select: none;
  position: relative;
}

.btn:active {
  background: grey;
}

.btn ul {
  display: none;
  list-style: none;
  color: black;
  flex-direction: column;
  margin: 0;
  padding: 2.5px 5px;
  left: 0;
  top: 50px;
  background: grey;
  border-radius: 15px;
  position: absolute;
}

.btn ul li {
  display: block;
  width: 90px;
  height: 35px;
  line-height: 35px;
  background: black;
  border-radius: 15px;
  color: white;
  margin: 2.5px 0;
}

.btn ul li:active {
  background: grey;
}

/* CHECKBOX CHEKCED */
#checkbox:checked + .btn ul {
  display: flex;
}
<input type="checkbox" id="checkbox">
<label class="btn" for="checkbox">
  <span id="selected">SELECT</span>
  <ul>
    <li onclick="selectList('Opt1')">Opt1</li>
    <li onclick="selectList('Opt2')">Opt2</li>
    <li onclick="selectList('Opt3')">Opt3</li>
  </ul>
</label>
  • So basically you need a working fuction that when the user clicks outside the dropdown, makes it close? – Nicola Spadari Jul 18 '22 at 13:58
  • yeah exactly, it has to be like a normal select list where you can close it by either choosing an option, clicking outside of it, or clicking on list itself. – WolfrevoKcats Jul 18 '22 at 14:05
  • probably want to verify it is not a checkbox and it is not a label connected to the checkbox – epascarello Jul 18 '22 at 14:08
  • Your `mouseup` event handler only checks if it is not the checkbox (or if the parent is not the checkbox, which is an impossibility, as `input`s are empty elements). If you want it to check for the select list, check for that element (i.e., the `label`), in addition to the checkbox. Or wrap both elements with another element and check to see if the event's target is contained within that. – Heretic Monkey Jul 18 '22 at 14:13
  • Does this answer your question? [How do I detect a click outside an element?](https://stackoverflow.com/questions/152975/how-do-i-detect-a-click-outside-an-element) – Heretic Monkey Jul 18 '22 at 14:14
  • commented js code already detects and closes menu on click outside of it, but it breaks checkbox so it is not closing when you choose options – WolfrevoKcats Jul 18 '22 at 14:19

1 Answers1

0

Your strategy uses css to style the state of the dropdown based on the radio option value.

So there's no event handler in place already catching that point in time and the only approach to close the dropdown when you click outside, was using a click event handler on the main document and check for the element triggering the event to be of type HTML. Not the best approach indeed. (I edited the question to use a better approach... there's a container having the class dropdown now and event.target gets checked for having an ancestor with such class to understand if the click was fired from the dropdown itself or outside of it)

document.addEventListener('click', function(event){      
  if(event.target.closest('.dropdown') === null){
    document.querySelector('#checkbox').checked  = false;
  }
});

Anyway once there, the logic just force the radio option to unchecked and restore the dropdown collapse state.

//SELECT FROM LIST
function selectList(id) {  
  let selected = document.getElementById('selected');
  selected.innerHTML = id;
}

document.addEventListener('click', function(event){      
  if(event.target.closest('.dropdown') === null){
    document.querySelector('#checkbox').checked  = false;
  }
});

//BREAKS CHECKBOX
//window.addEventListener('mouseup', function(event){
//  let checkbox = document.getElementById('checkbox');
//  if (event.target != checkbox && event.target.parentNode != checkbox){
//    checkbox.checked = false;
//  }
// });
.btn {
  display: block;
  width: 100px;
  height: 50px;
  text-align: center;
  color: white;
  background: black;
  border-radius: 15px;
  line-height: 50px;
  cursor: pointer;
  user-select: none;
  position: relative;
}

.btn:active {
  background: grey;
}

.btn ul {
  display: none;
  list-style: none;
  color: black;
  flex-direction: column;
  margin: 0;
  padding: 2.5px 5px;
  left: 0;
  top: 50px;
  background: grey;
  border-radius: 15px;
  position: absolute;
}

.btn ul li {
  display: block;
  width: 90px;
  height: 35px;
  line-height: 35px;
  background: black;
  border-radius: 15px;
  color: white;
  margin: 2.5px 0;
}

.btn ul li:active {
  background: grey;
}

/* CHECKBOX CHEKCED */
#checkbox:checked + .btn ul {
  display: flex;
}
<div class="dropdown">

  <input type="checkbox" id="checkbox">
  <label class="btn" for="checkbox">
    <span id="selected">SELECT</span>
    <ul>
      <li onclick="selectList('Opt1')">Opt1</li>
      <li onclick="selectList('Opt2')">Opt2</li>
      <li onclick="selectList('Opt3')">Opt3</li>
    </ul>
  </label>
  
</div>
Diego D
  • 6,156
  • 2
  • 17
  • 30