0

I'm encountering an weird issue in javascript, playing with .focus() function and css transition.

See the jsFiddle below.

I have a modal with a search input in it. On click on the #trigger, it add a class to the modal and a focus() to input (to improve user experience).

And it works great until... I use CSS transition to make it appear smoother (on opacity and visibility properties).

Any ideas where this issue could be coming from?

Thanks in advance!

let trigger = document.getElementById('trigger'),
    closer = document.getElementById('closer'),
    box = document.getElementById('wrapper'),
    sInput = document.getElementById('search__input')
    
trigger.addEventListener('click', () => {
  box.classList.add('is-visible')
  sInput.focus()
})

closer.addEventListener('click', () => {
  box.classList.remove('is-visible')
})
#wrapper {
  position: fixed;
  top: 0; left: 0; right: 0;
  width: 100%; height: 100%;
  
  background: rgba(0, 0, 0, 0.8);
  
  visibility: hidden;
  opacity: 0;
  
  transition: opacity .1s linear, visibility .1s linear .1s;
}

#wrapper.is-visible {
  opacity: 1;
  visibility: visible;
  
  transition: visibility .1s linear, opacity .1s linear .1s;
}

#closer {
  position: absolute;
  top: 10px; left: 10px;
  color: #000;
  background-color: white;
}

#search__input {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  padding: 10px;
  font-size: 24px;
}
<a href="#" id="trigger">Click me.</a>

<div id="wrapper">
  <a href="#" id="closer">Close me.</a>
  <input type="search" placeholder="Search here" id="search__input"/>
</div>

Same idea without CSS transition

let trigger = document.getElementById('trigger'),
    closer = document.getElementById('closer'),
    box = document.getElementById('wrapper'),
    sInput = document.getElementById('search__input')

trigger.addEventListener('click', () => {
  box.classList.add('is-visible')
  sInput.focus()
})

closer.addEventListener('click', () => {
  box.classList.remove('is-visible')
})
#wrapper {
  position: fixed;
  top: 0; left: 0; right: 0;
  width: 100%; height: 100%;

  background: rgba(0, 0, 0, 0.8);

  visibility: hidden;
  opacity: 0;
}

#wrapper.is-visible {
  opacity: 1;
  visibility: visible;
}

#closer {
  position: absolute;
  top: 10px; left: 10px;
  color: #000;
  background-color: white;
}

#search__input {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  padding: 10px;
  font-size: 24px;
}
<a href="#" id="trigger">Click me.</a>

<div id="wrapper">
  <a href="#" id="closer">Close me.</a>
  <input type="search" placeholder="Search here" id="search__input"/>
</div>
Alexis Wollseifen
  • 441
  • 1
  • 6
  • 21

2 Answers2

2

That is happening because an element that is hidden, not displayed or with opacity, can't be focused, by the time of the transition your element can't be focused..

Why changing visibility/display on focus does not work?

to fix it I will recomend using a timeout callback

let trigger = document.getElementById('trigger'),
    closer = document.getElementById('closer'),
    box = document.getElementById('wrapper'),
    sInput = document.getElementById('search__input')
    
trigger.addEventListener('click', function() {
  box.classList.add('is-visible');
  setTimeout(()=>{
    sInput.focus();
  },1000);
  
})

closer.addEventListener('click', () => {
  box.classList.remove('is-visible')
})
#wrapper {
  position: fixed;
  top: 0; left: 0; right: 0;
  width: 100%; height: 100%;
  
  background: rgba(0, 0, 0, 0.8);
  
  visibility: hidden;
  opacity: 0;
  
  transition: opacity .1s linear, visibility .1s linear .1s;
}

#wrapper.is-visible {
  opacity: 1;
  visibility: visible;
  
  transition: visibility .1s linear, opacity .1s linear .1s;
}

#closer {
  position: absolute;
  top: 10px; left: 10px;
  color: #000;
  background-color: white;
}

#search__input {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  padding: 10px;
  font-size: 24px;
}
<a href="#" id="trigger">Click me.</a>

<div id="wrapper">
  <a href="#" id="closer">Close me.</a>
  <input type="search" placeholder="Search here" id="search__input"/>
</div>
Renzo Calla
  • 7,486
  • 2
  • 22
  • 37
  • Hi ! Thanks for your answer, in the meantime I've found the same reason and wrote my answer. Thanks for the link. In this case, CSS aren't actually needful on the "opening" part. So I use transition on opacity only first and then on opacity & visibility. – Alexis Wollseifen Oct 31 '17 at 13:22
2

Alright, I tried many things and I found out what was the problem here.

element.focus() will not affect its target if this target is visibility: hidden. I actually thought it was the case only with display: none property but it seem that unpainted element cannot be focused.

I answer my own question, but I leave it here, it maybe will help someone.

CLOSED.

Alexis Wollseifen
  • 441
  • 1
  • 6
  • 21