javascripthtmltwitter-bootstrapdrop-down-menubootstrap-5

How to activate first menu item on dropdown click in Bootstrap 5


I have a Bootstrap 5 dropdown defined as

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js"></script>

<div class="btn-group">
  <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Action
  </button>
  <ul class="dropdown-menu">
<li><a class="dropdown-item" href="#"><u>A</u>ction</a></li>
<li><a class="dropdown-item" href="#">A<u>n</u>other action</a></li>
<li><a class="dropdown-item" href="#"><u>S</u>omething else here</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">S<u>e</u>parated link</a></li>
  </ul>
</div>

If clicked in Action button, first menu item Action is not active (highlighted):

enter image description here

Pressing down arrow is required to activate it:

enter image description here

How to fix it so that opening dropdown highlights first item like in normal windows desktop application menus?

https://jsfiddle.net/b6or2s5e/


Solution

  • You can simply add the built in active class in bootstrap and it will give you a blue background. Just get the first link in the dropdown menu and add active to its classList.

    There are some caveats though when using Boot Strap. Overriding BS classes can often be challenging. With the a tags classes set to dropdown-item the background is set to 'transparent' by default, this can not be overridden with a class unless your class comes from a css style sheet with the same name and place under the BS CSS CDN. But inline style will override the background.

    Also if you want hover effects on the drop down menu items, you can use JS eventListeners to set inline styles as I have done with the code in the snippet.

    If you only want the first item set -

    document.addEventListener("DOMContentLoaded", function() {
      // using built in active class from bootstrap
      // use querySelector() to get first occurance of an element
      const sections = document.querySelector('li a');
      // get first element of the nodelist and add active class to classList
      sections.classList.add('active');
    
      // using inline style to override BS dorpdow-item class
      const dropdown2 = document.querySelectorAll('.dropdown-menu')[1];
      const sections2 = dropdown2.querySelector('li a');
      sections2.style.backgroundColor = 'rgb(225,225,255)';
    });
    /* added to remove any mouseover events from firing on hover of underlined element */
    
    u {
      pointer-events: none;
    }
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
    <div class="d-flex justify-content-around">
      <!-- Example single danger button -->
      <div class="btn-group">
        <!--/ Added the id dropdown-btn for this example /-->
        <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
        Action
      </button>
        <ul class="dropdown-menu">
          <li><a class="dropdown-item" href="#section1"><u>A</u>ction</a></li>
          <li><a class="dropdown-item" href="#section2">A<u>n</u>other action</a></li>
          <li><a class="dropdown-item" href="#section3"><u>W</u>e have a link</a></li>
          <li><a class="dropdown-item" href="#section4"><u>S</u>omething else here</a></li>
          <li>
            <hr class="dropdown-divider">
          </li>
          <li><a class="dropdown-item" href="#section5">S<u>e</u>parated link</a></li>
        </ul>
      </div>
      <!--/ added purely for example /-->
      <div id="vertical-space">
      </div>
      <br><br>
      <!-- Example single danger button -->
      <div class="btn-group">
        <!--/ Added the id dropdown-btn for this example /-->
        <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
        Action
      </button>
        <ul class="dropdown-menu">
          <li><a class="dropdown-item" href="#section1"><u>A</u>ction</a></li>
          <li><a class="dropdown-item" href="#section2">A<u>n</u>other action</a></li>
          <li><a class="dropdown-item" href="#section3"><u>W</u>e have a link</a></li>
          <li><a class="dropdown-item" href="#section4"><u>S</u>omething else here</a></li>
          <li>
            <hr class="dropdown-divider">
          </li>
          <li><a class="dropdown-item" href="#section5">S<u>e</u>parated link</a></li>
        </ul>
      </div>
      <!--/ added purely for example /-->
      <div id="vertical-space">
      </div>
    </div>

    If you want mouseover (hover) on the other links -

    document.addEventListener("DOMContentLoaded", function() {
      const dropdownMenu = document.querySelector('.dropdown-menu');
      const action = document.querySelector('.btn');
      const sections = dropdownMenu.querySelectorAll('li a');
      // get first element of the nodelist and set to active
      sections[0].classList.add('active');
      // override the bootstrap dropdown-item classes background
      // which is set to transparent by default
      // while built in class `active` is present 
      // using a method with mouseover/mouseout events
      const highlight = (e) => {
        // conditional event type is mouseover and target is not the active class
        if(e.type === 'mouseover' && !e.target.classList.contains('active')){
          // override the bootstrap transparent background 
          // using inline styles for hovered links
          e.target.style.backgroundColor = 'rgb(225, 225, 225)';
        // else if conditional for mouseout and target is not the active class
        }else if(e.type === 'mouseout' && !e.target.classList.contains('active')){  
          // reset the bootstrap transparent background using inline styles  
          e.target.style.backgroundColor = 'transparent';
        }
      }
      // loop over the dropdown links and add eventListsners calling highlight method
      sections.forEach(sec => {
        sec.addEventListener('mouseover', highlight);
        sec.addEventListener('mouseout', highlight);
      })
    });
    /* added to remove any mouseover events from firing on hover of underlined element */
    u {
      pointer-events: none;
    }
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
    
    <!-- Example single danger button -->
    <div class="btn-group">
      <!--/ Added the id dropdown-btn for this example /-->
      <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
        Action
      </button>
      <ul class="dropdown-menu">
        <li><a class="dropdown-item" href="#section1"><u>A</u>ction</a></li>
        <li><a class="dropdown-item" href="#section2">A<u>n</u>other action</a></li>
        <li><a class="dropdown-item" href="#section3"><u>W</u>e have a link</a></li>
        <li><a class="dropdown-item" href="#section4"><u>S</u>omething else here</a></li>
        <li>
          <hr class="dropdown-divider">
        </li>
        <li><a class="dropdown-item" href="#section5">S<u>e</u>parated link</a></li>
      </ul>
    </div>
    <!--/ added purely for example /-->
    <div id="vertical-space">
    </div>

    You could also define your own style for the first item using inline styles -

    document.addEventListener("DOMContentLoaded", function() {
      const dropdownMenu = document.querySelector('.dropdown-menu');
      const action = document.querySelector('.btn');
      const sections = dropdownMenu.querySelectorAll('li a');
      // get first element of the nodelist and background-color
      sections[0].style.backgroundColor = 'rgb(190, 190, 190)';
      // override the bootstrap dropdown-item classes background
      // which is set to transparent by default
      // while built in class `active` is present 
      // using a method with mouseover/mouseout events
      const highlight = (e) => {
        // conditional event type is mouseover and target is not the first item
        if(e.type === 'mouseover' && e.target !== sections[0]){
          // override the bootstrap transparent background 
          // using inline styles for hovered links
          e.target.style.backgroundColor = 'rgb(225, 225, 225)';
        // else if conditional for mouseout andtarget is not the first item
        }else if(e.type === 'mouseout' && e.target !== sections[0]){  
          // reset the bootstrap transparent background using inline styles  
          e.target.style.backgroundColor = 'transparent';
        }
      }
      // loop over the dropdown links and add eventListsners calling highlight method
      sections.forEach(sec => {
        sec.addEventListener('mouseover', highlight);
        sec.addEventListener('mouseout', highlight);
      })
    });
    /* added to remove any mouseover events from firing on hover of underlined element */
    u {
      pointer-events: none;
    }
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
    
    <!-- Example single danger button -->
    <div class="btn-group">
      <!--/ Added the id dropdown-btn for this example /-->
      <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
        Action
      </button>
      <ul class="dropdown-menu">
        <li><a class="dropdown-item" href="#section1"><u>A</u>ction</a></li>
        <li><a class="dropdown-item" href="#section2">A<u>n</u>other action</a></li>
        <li><a class="dropdown-item" href="#section3"><u>W</u>e have a link</a></li>
        <li><a class="dropdown-item" href="#section4"><u>S</u>omething else here</a></li>
        <li>
          <hr class="dropdown-divider">
        </li>
        <li><a class="dropdown-item" href="#section5">S<u>e</u>parated link</a></li>
      </ul>
    </div>
    <!--/ added purely for example /-->
    <div id="vertical-space">
    </div>

    Here is an example using your other question with the underlined elements code mashed in to one snippet on JS Fiddle