Instructions on how to use a keyboard key to activate a dropdown menu item in Bootstrap

Bootstrap 5 navbar features dropdown menus that have underlined hotkeys such as a,n,s, and e.

https://i.sstatic.net/bZOaC1kU.png

<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 a key on the keyboard is pressed, how can the corresponding menu item be activated? For instance, when the dropdown menu is open, pressing "A" should act as though the "Action" menu item is clicked.

jsfiddle: https://jsfiddle.net/b6or2s5e/

Handling of left and right arrow keys is already implemented.

How to use left and right arrow keys to navigate in bootstrap navbar

document.addEventListener("DOMContentLoaded", function () {
  document.querySelectorAll('.dropdown').forEach(function (el) {
    el.addEventListener('shown.bs.dropdown', function () {
      document.addEventListener('keydown', function (e) {
        const click = new MouseEvent("click", {
          bubbles: true,
          cancelable: true,
          view: window,
        })
        if (e.key === "ArrowRight") {
          const o = getNextSibling(e.target.closest('.dropdown'), '.dropdown')
          if (!o) {
            document.querySelector('.dropdown-toggle').dispatchEvent(click)
          } else {
            o.querySelector('.Xdropdown-toggle').dispatchEvent(click)
          }
        } else if (e.key === "ArrowLeft") {
          const o = getPrevSibling(e.target.closest('.dropdown'), '.dropdown')
          if (!o) {
            const ar = document.querySelectorAll('.dropdown-toggle')
            ar[ar.length - 1].dispatchEvent(click)
          } else {
            o.querySelector('.dropdown-toggle').dispatchEvent(click)
          }
        }
      }, { once: true })
    })
  })
})

How can hotkey handling be added as well?

Answer №1

Here is an improved code snippet that utilizes a dynamic approach. It identifies the underlined elements and uses a forEach loop to compare a keydown event on the window with each element's textContent converted to lowercase. If a match is found, it triggers a click() event on the matching element.

Is it possible to remove the switch statement and call findUnderlined for any key when alt or ctrl is not pressed?

It is feasible to add conditions for specific keys you want to control with the keydown event. Simply adjust the logic within the conditional statement as needed.

For more details, refer to the revised snippet below...

document.addEventListener("DOMContentLoaded", function() {
  const dropdownMenu = document.querySelector('.dropdown-menu');
  const action = document.querySelector('#dropdown-btn');
  const sections = dropdownMenu.querySelectorAll('li u');
  const setClickForUnderlinedEls = (els, key) => {
    els.forEach(sec => {
      if (key === sec.textContent.toLowerCase()) {
        sec.click()
      }
    });
  }
  action.addEventListener('click', (event) => {
    addEventListener('keydown', (e) => {
      if (event.target.ariaExpanded !== 'false') {
        setClickForUnderlinedEls(sections, e.key);
      }
    });
  })
});

document.addEventListener("DOMContentLoaded", function() {
  const dropdownMenu = document.querySelector('.dropdown-menu');
  const action = document.querySelector('#dropdown-btn');
  const sections = dropdownMenu.querySelectorAll('li u');
  const setClickForUnderlinedEls = (els, key) => {
    els.forEach(sec => {
      if (key === sec.textContent.toLowerCase()) {
        sec.click()
      }
    });
  }
  action.addEventListener('click', (event) => {
    addEventListener('keydown', (e) => {
      if (event.target.ariaExpanded !== 'false') {
        setClickForUnderlinedEls(sections, e.key);
      }
    });
  })
});
#vertical-space,
#section1,
#section2,
#section3,
#section4,
#section5{
  height: 100vh;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

<!-- Example single danger button -->
<div class="btn-group" id="top">
  <!--/ Added the id dropdown-btn for this example /-->
  <button id="dropdown-btn" 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 id="section1">
  <p>
    You pressed the <strong>a</strong> button and instantiated a click on the <em>Action</em> button. <a href="#top">Back to top</a>
  </p>
  
</div>
<div id="section2">
  <p>
    You pressed the <strong>n</strong> button and instantiated a click on the <em>Another action</em> button. <a href="#top">Back to top</a>
  </p>
</div>
<div id="section3">
  <p>
    You pressed the <strong>w</strong> button and instantiated a click on the <em>We have a link</em> button. <a href="#top">Back to top</a>
  </p>
</div>
<div id="section4">
  <p>
    You pressed the <strong>s</strong> button and instantiated a click on the <em>Something else here</em> button. <a href="#top">Back to top</a>
  </p>
</div>
<div id="section5">
  <p>
    You pressed the <strong>e</strong> button and instantiated a click on the <em>Separate link</em> button. <a href="#top">Back to top</a>
  </p>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I identify the main text of a specific <MenuItem/> component in ReactJS Material-UI?

I've been working with the Material-UI Dropdown Menu component and I'm trying to figure out how to console log the primaryText of the selected <MenuItem/>. Can anyone provide guidance on how to achieve this? ...

Enhancing the efficiency of a JavaScript smooth scrolling feature for numerous listed items

I have been experimenting with recreating the recent Apple Mac retrospective using only CSS and JavaScript to create a small timeline of projects. While I have successfully implemented the layout for the full-screen hero and the expand-on-hover effect, I a ...

Placeholder fails to appear

After implementing some jQuery validation, I wanted to display a text as a placeholder when the user skipped out of an input field without entering anything. This is the code I wrote: $('input[type="text"]').on('blur', function() { ...

Ajax-powered Datatables

I am a beginner to data tables and I am attempting to retrieve data from a JSON text file (test1.txt). Below is an excerpt of the data present in the file, which contains over 5000 entries: [{"0":"22352442","ID":"22352442","1":"22126303","PARENT":"2212630 ...

Encountering repeated requests (duplicating calls) for each API request while using AngularJS with a JWT authentication token

I'm experiencing a problem with AngularJS(2/4) while attempting to make API calls. The issue arises when each API request contains a JWT Auth Token header, resulting in duplicate API calls. The first request returns no response (despite receiving a 20 ...

Tips for clicking a .class a random number of times:

Could someone help me figure out how to click a random number of times on the element with class name .CLASS when a key is pressed? I think I need to incorporate the Math.floor(Math.random()) function, but I'm not sure how to do it in my existing code ...

Utilizing a filter within the ng-model directive

I have a question about using a filter with an h3 element. Here is the code snippet: {{ event.date | date:'dd-MM-yyyy' }} It's working perfectly fine and Angular is formatting the date as expected. However, when I try to use the same filte ...

Node's Input Standardization

While I have been delving into the basics of JS and coding in Sublime, I recently made the transition to VSCode. This shift has left me feeling somewhat lost as I attempt to find alternatives to using prompt(). My previous coding method looked like this: ...

Receiving a Javascript Callback from Paypal

Is it possible to receive a JavaScript callback after a successful PayPal purchase made using a button? I am aware of IPN, but it requires a return URL. My main goal is to simply determine if a user has completed a purchase with the button. ...

Bootstrap 4.0. When it comes to buttons, they seem to have trouble cooperating with other DIV elements

Today is my first time seeking help on StackOverflow: I'm encountering an issue with my website where the floating arrow at the bottom of the page is obstructing my ability to click on buttons. Whether it's a Bootstrap button or HTML button, non ...

What is causing my conditional operator to malfunction?

What is the reason for the output being undefined instead of "old" in this scenario? function test(age) { return 12 < age ? "old" : "young"; } test(15); ...

Navigating in a Curved Path using Webkit Transition

Currently, I am working on a simple project to learn and then incorporate it into a larger project. I have a basic box that I want to move from one position to another using CSS webkit animations and the translate function for iOS hardware acceleration. I ...

Utilize NodeJS to dynamically alter the text outputted on an HTML page

For educational purposes, I am designing a website where users can sign in by entering their name on the login page. After signing in, they will be redirected to the home page which displays a personalized welcome message using their name. I have included ...

The Workbench has "Rejected the setting of an insecure header 'content-length'"

While working on implementing a simple xhr abstraction, I encountered a warning when trying to set the headers for a POST request. Strangely, I noticed that the issue might be related to setting the headers in a separate JavaScript file. This is because wh ...

A step-by-step guide to implementing lodash once in Vuejs

I am faced with the following input scenario. <input type="text" maxlength="50" v-on:input="query = $event.target.value" v-on:keyup.enter="once(search)" /> Additionally, there are ...

jQuery AJAX POST Request Fails to SendIt seems that the

The issue I am experiencing seems to be directly related to the jQuery $.ajax({...}); function. In PHP, when I print the array, I receive a Notice: Undefined index. I would greatly appreciate any advice or guidance on this matter. <script> $(docume ...

Looking to change the input field names by increasing or decreasing when clicking on a div using jQuery?

As a beginner in the world of jQuery, I am working on mastering some basic concepts. Currently, my goal is to create auto incrementing/decrementing input field names within a 'div' when clicking on an add/remove button. Below is the HTML code I a ...

Express backend not receiving form data from post request

I recently created a form to submit a file to an express backend, but I'm encountering an issue where the data is not being received on the backend when the form is submitted. Upon using console.log, I noticed that req.body returns {}, and sampleFile ...

How to create horizontal spacing between divs using Bootstrap 3

I am struggling to create a small horizontal space between the "Away Team" and "Baseball Field" divs in my code. I have tried adjusting padding, margins, and even adding decimal column offsets without any success. The desired spacing effect can be seen in ...

Is it possible to transform a Vuejs project into Vue-Native?

I recently completed a Vue.js project and now I'm interested in turning it into a native app. I'm wondering if I'll need to completely rewrite the application using Vue-Native components, or if there is a way to convert my existing project i ...