How to trigger a event listener on element before hide it

I got a input box, when the focus event fired on it, a list of prompt text will show up below the input box, and when blur event is fired, list will be hidden.

I add click event listener on the list of prompt, but when I try to click the prompt, blur event on the input box fired first so the click event on the prompt never get fired.

Is there a way to make click event on the prompt text fire first? After that I will fire the blur event handler to hide the prompt text.

var textEl = document.getElementById("text"),
  listEl = document.getElementById("list");

textEl.onfocus = function() {
  listEl.style.display = "initial";
}

textEl.onblur = function() {
  listEl.style.display = "none";
}

listEl.onclick = function(event) {
  var item = event.target;
  alert(item.textContent);
  textEl.value = item.textContent;
}
#container {
  position: relative;
  width: 300px;
  margin: auto;
}

input {
  width: 100%;
}

#list {
  display: none;
  position: absolute;
  width: 100%;
  background: #fff;
}

.item {
  padding: 12px 0;
  border-bottom: 1px solid #ccacac;
}
<div id="container">
  <input type="text" id="text">

  <div id="list">
    <div class="item"> item 1</div>
    <div class="item"> item 2</div>
    <div class="item"> item 3</div>
  </div>

</div>

Answer

You could use mouseenter and mouseleave on listEl to decide whether or not the textEl should response to the blur event. So, based on that, you could just attach/detach the blur handler.

var textEl = document.getElementById("text"),
  listEl = document.getElementById("list");

textEl.onfocus = function() {
  listEl.style.display = "initial";
}

var blurHandler = function() {
  listEl.style.display = "none";
};

textEl.onblur = blurHandler;

listEl.onclick = function(event) {
  var item = event.target;
  alert(item.textContent);
  textEl.value = item.textContent;
}

listEl.onmouseenter = function(event) {
  textEl.onblur = null;
}

listEl.onmouseleave = function(event) {
  textEl.onblur = blurHandler;
  
  // Also trigger the blur handler, if the element is not in focus.
  if(document.activeElement.id !== "text"){
    blurHandler();
  }
}
#container {
  position: relative;
  width: 300px;
  margin: auto;
}

input {
  width: 100%;
}

#list {
  display: none;
  position: absolute;
  width: 100%;
  background: #fff;
}

.item {
  padding: 12px 0;
  border-bottom: 1px solid #ccacac;
}

.item:hover {
  padding: 12px 0;
  border-bottom: 1px solid #ccacac;
  color: red;
}
<div id="container">
  <input type="text" id="text">

  <div id="list">
    <div class="item"> item 1</div>
    <div class="item"> item 2</div>
    <div class="item"> item 3</div>
  </div>

</div>

Or, you could use some CSS for it. For instance, you could set the display: block on list, when the input is being hovered on, or is in focus; or the list itself is in focus or is being hovered on.

#text:focus ~ #list, #list:focus,
#text:hover ~ #list, #list:hover{
  display: block;
}

Since it gets rid of those JS event handlers, I’d say it is preferable among the two.

var textEl = document.getElementById("text"),
  listEl = document.getElementById("list");


listEl.onclick = function(event) {
  var item = event.target;
  alert(item.textContent);
  textEl.value = item.textContent;
}
#container {
  position: relative;
  width: 300px;
  margin: auto;
}

#list {
  display: none;
  position: absolute;
  width: 100%;
  background: #fff;
}

#text:focus ~ #list, #list:focus,
#text:hover ~ #list, #list:hover{
  display: block;
}

input {
  width: 100%;
}

.item {
  padding: 12px 0;
  border-bottom: 1px solid #ccacac;
}

.item:hover {
  padding: 12px 0;
  border-bottom: 1px solid #ccacac;
  color: red;
}
<div id="container">
  <input type="text" id="text">

  <div id="list">
    <div class="item"> item 1</div>
    <div class="item"> item 2</div>
    <div class="item"> item 3</div>
  </div>

</div>