Skip to content

Instantly share code, notes, and snippets.

@jreviews
Last active July 25, 2023 11:42
Show Gist options
  • Save jreviews/babfe37c4c57116395ea8afa3fafc322 to your computer and use it in GitHub Desktop.
Save jreviews/babfe37c4c57116395ea8afa3fafc322 to your computer and use it in GitHub Desktop.
Vivaz template - open dropdowns on hover
<script>
window.addEventListener('DOMContentLoaded', (event) => {

  // Iterate through each main link in the topbar navigation. 
  document.querySelectorAll('.mod-menu > li > a').forEach((mainLink) => {
    const mainLi = mainLink.closest('li'); // Find the closest parent 'li'.
    const mainDropdownElement = mainLi.querySelector('.dropdown-menu'); // Select the dropdown menu of the main link.

    // Execute if both the main link and associated dropdown menu exist.
    if(mainLink && mainDropdownElement) {
      
      // Create a new dropdown instance or get an existing one, with set options.
      const mainDropdown = bootstrap.Dropdown.getOrCreateInstance(mainLink, { 
        boundary: 'viewport', 
        autoClose: false 
      });

      // On hover over the main link, show its dropdown and hide others.
      mainLi.addEventListener('mouseenter', () => {
        
        // Iterate through each topbar navigation link to close their dropdowns, except for the currently hovered-over main link.
        document.querySelectorAll('.topbar > li > a').forEach((link) => {
          const li = link.closest('li');
          if(li !== mainLi){
            const dropdownElement = li.querySelector('.dropdown-menu');
            if(link && dropdownElement) {
              const dropdown = bootstrap.Dropdown.getInstance(link);
              if(dropdown)
                dropdown.hide();
            }
          }
        });

        // Show current main link's dropdown.
        mainDropdown.show();
      });

      // On mouse leave from the main link, decide whether to hide its dropdown or not, based on mouse position.
      mainLi.addEventListener('mouseleave', (e) => {

        let rect = mainLi.getBoundingClientRect(); // Get dimensions of main link.
        let dropdownRect = mainDropdownElement.getBoundingClientRect(); // Get dimensions of dropdown of main link.

        let leftSide = rect.left + rect.width; // Right side border of main link.
        let rightSide = dropdownRect.left; // Left side border of dropdown.
        let bottomSide = rect.top + rect.height; // Bottom side border of main link.
        let topSide = dropdownRect.top; // Top side border of dropdown.

        // If mouse leaves outside the margin space of link and dropdown, hide the dropdown.
        if (e.clientX < leftSide || e.clientX > rightSide || e.clientY < topSide || e.clientY > bottomSide) {
          
          // Exceptionally, if mouse moved to a different 'li', hide the dropdown anyway.
          if (e.target !== mainLink && e.relatedTarget === null) {
            mainDropdown.hide();
          }
        } else {
          // Inside the margin space, if mouse moved to another element within the same dropdown, do not hide it.
          if (e.target === e.relatedTarget) {
            mainDropdown.show();
          } else {
            mainDropdown.hide();
          }
        }
      });
    }
  });
  
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment