Search code examples
javascriptcssfrontendhovertooltip

How to use javascript to remove focus/hover state on click in mobile


I have a tooltip that appears on hover. The problem is that in order to remove focus/hover state in mobile, you have to click outside of the .explanation div. I want to mak it so that you can also close it my

<div class="main">
  <div>
    <h5>h5 text</h5>
      <div class="explanation">
        <div>
          <p>An explanatory paragraph <a>x</a>
          </p>
        </div>
      </div>
  </div>
</div>

css looks like this:

.main {
  .explanation {
    &::before {
      content: "[hover to show]";
    }

    p {
      background: #edf6ff;
      display: none;
      margin: 0;
      padding: 12px;
      position: relative;
      width: 200px;
      
      a {
        
          content: '[close]';
          outline: 5px solid blue;
          position: absolute;
          top: -5px;
          right: -20px;
        }
    }

    &:hover p {
      display: block;
    }
  }
}

jsfiddle here

This works perfectly on desktop, but ON MOBILE I want to be able to remove the focus on the element by clicking on the [x] a tag. You can already close it by clicking anywhere else, but I want to be able to click the X (which is inside) to close as well.

I figure it will be something like:

const closeButton = document.querySelector(
    '.main .explanation p a'
);

const main = document.querySelector('.main');

closeButton.addEventListener('click', removeFocus, false);

function removeFocus(event) {
    main.blur();
    event.preventDefault();
}

But this doesn't do anything, at least not in Chrome. How can I toggle off the hover state on mobile?


Solution

  • Instead of css hover use mouseenter and mouseleave. On mouseenter or touchstart add active class and on mouseleave remove it. When we click on close button remove the class

    const closeButton = document.querySelector('.main .explanation p a');
    const explanation = document.querySelector('.main .explanation');
    const addActiveClass = (e) => {
        explanation.classList.add('active');
    }
    const removeActiveClass = (e) => {
        explanation.classList.remove('active');
    }
    
    closeButton.addEventListener('click', toggleExplanation, false);
    explanation.addEventListener('mouseenter', addActiveClass);
    explanation.addEventListener('mouseleave', removeActiveClass);
    explanation.addEventListener('touchstart', addActiveClass);
    
    function toggleExplanation(event) {
      explanation.classList.toggle('active');
      event.preventDefault();
    }
    
    document.addEventListener('click', function(e) {
    
      // Check if the clicked element is outside the target element
      if (!explanation.contains(e.target)) {
        removeActiveClass(e)
      }
    });
    .main {
      .explanation {
        &::before {
          content: "[hover to show]";
        }
    
        p {
          background: #edf6ff;
          display: none;
          margin: 0;
          padding: 12px;
          position: relative;
          width: 200px;
    
          a {
            content: '[close]';
            outline: 5px solid blue;
            position: absolute;
            top: -5px;
            right: -20px;
          }
        }
    
        &.active p {
          display: block;
        }
      }
    }
    <div class="main">
      <div>
        <h5>h5 text</h5>
          <div class="explanation">
            <div>
              <p>An explanatory paragraph <a>x</a>
              </p>
            </div>
          </div>
      </div>
    </div>