4

We can use Tab key in the keyboard to cycle fucus on inputs and buttons.

We can also use Space key to kinda click on a button when one is on focus.

Take the demo below for example, if you press Tab multiple times, you will cycle through the inputs, and when you press Space when the <button>Popup</button> is on focus, you will see a popup with another two buttons.

Now, when you keep pressing Tab, you will see the focus cycle outside of the popup.

popup.addEventListener('click', function(){
  overlay.classList.add('active');
});

overlay.addEventListener('click', function(e){
  if (e.target === overlay)
    overlay.classList.remove('active');
});
input {
  display: block;
}

input:nth-child(3){
  display: inline-block;
}

button {
  margin: 0 0.25em;
}

#overlay {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.25);
  display: none;
}

#overlay.active {
  display: flex;
  justify-content: center;
  align-items: center;
}

#container {
  width: 300px;
  background-color: #fff;
  padding: 1em;
  display: flex;
  justify-content: flex-end;
}
<input>
<input>
<input><button id="popup">Popup</button>
<input>
<input>

<div id="overlay">
  <div id="container">
    <button>Cancel</button>
    <button>OK</button>
  </div>
</div>

Is there a built-in way to bound the cycle group within a defined scope (i.e., parent element) so that the tabbing will only cycle through the sibling elements?

Edit

I know how to do it with JavaScript, but it feels overly complicated for a seemingly simple functionality. So I'm kinda looking for a non-JS alternative (i.e., HTML built-in attribute, CSS properties) or a JS solution (not jQuery) that relates to maybe a built-in HTMLElement properties that I haven't heard of.

  • Possible duplicate of How to create tabindex groups? – Justinas Jun 7 at 9:52
  • 1
    Not that I know of, since tabbing is intended to be able to reach all tabbable elements on a page. Same way that continuing to tab inside this SO stack snippet will jump outside to the SO page. What you could do, is temporarily put a negative tabindex on all elements that should not be tabbable and remove them again when the popup closes. That would work for form elements like inputs and buttons, but not like tabbable divs and spans. Else you're stuck with detecting the tab key and manually preventing focus and such with JS code as shown in the duplicate. – Shilly Jun 7 at 9:53
  • Sounds like you are trying to achieve the "Roving tabindex" technique. You can read up on it here - under the heading "Managing focus in components" – ScottieG Jun 7 at 9:55
  • Only when being marked as a duplicate I understand that jQuery is the new JavaScript. – Yong Quan Jun 7 at 10:05
  • In the same page @ScottieG mentioned, check the section "Modals and keyboard traps", that provides a solution to your problem – AvcS Jun 7 at 10:14
0

Yes, this is an example of HTML with simple Javascript events attached. I still use your example code with the button event so thats why there is separate JS, but all logic is in the html.

popup.addEventListener('click', function(){
  overlay.classList.add('active');
});

overlay.addEventListener('click', function(e){
  if (e.target === overlay)
    overlay.classList.remove('active');
});
input {
  display: block;
}

input:nth-child(3){
  display: inline-block;
}

button {
  margin: 0 0.25em;
}

#overlay {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.25);
  display: none;
}

#overlay.active {
  display: flex;
  justify-content: center;
  align-items: center;
}

#container {
  width: 300px;
  background-color: #fff;
  padding: 1em;
  display: flex;
  justify-content: flex-end;
}
<span tabindex=1 onFocus="document.querySelector('.autofocus2').focus()">Top cycke</span>
<input class="autofocus1" tabindex="2" autofocus="">
<input  tabindex="3">
<input  tabindex="4">
<button id="popup"  tabindex="5">Popup</button>
<input  tabindex="9">
<input  tabindex="10">

<div id="overlay">
  <div id="container">
    <span autofocus="" onFocus="document.querySelector('.innerautofocus2').focus()"></span>
    <button  tabindex="6" class="innerautofocus1">Cancel</button>
    <button tabindex="7" class="innerautofocus2" >OK</button>
    <span tabindex="8" onFocus="document.querySelector('.innerautofocus1').focus()">   </span>
  </div>
</div>

<span tabindex=11 onFocus="document.querySelector('.autofocus1').focus()">End Cycle</span>

The behavior as follows: The HTML autofocus even triggers focus on the first item with tabindex 2. Subsequent tabs will loop through all tabindexes in order, skipping hidden options. As you see without the popup box, indexes 6-8 are skipped. When it reaches the end, autofocus triggers a new focus set on the first item in the list.

With the popup box active, a new set of autofocus triggers set the inner loop of tabs with the same logic as above

  • OP asked if it was possible WITHOUT JavaScript. You have provided a solution WITH JavaScript. – ScottieG Jun 7 at 13:39
  • but OP said "...or a JS solution (not jQuery) that relates to maybe a built-in HTMLElement" – pastaleg Jun 7 at 13:44
  • Ah, I see he's edited it since I last read it this morning. – ScottieG Jun 7 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.