How to stop browser auto scrolling containers on focus changes - javascript

As you tab between input fields in a browser, the browser will automatically scroll the nearest parent container to place the next focused field within the view.
Simple JSFiddle: http://jsfiddle.net/TrueBlueAussie/pxyXZ/1/
$('.section').eq(6).find('input').focus();
For example if you open the above fiddle it selects "Sample item 7" at the bottom of the yellow window. If you press tab the "Sample text 8" field jumps up towards the middle of the parent window.
Obviously this is a great thing for normal websites, but I have a custom scrolling container in which I position & scroll everything manually. I am tracking focus changes and will use a momentum scroller to bring it into view, but how do I disable the default scrolling behavior of web-browsers? Happy to accept CSS, Javascript or JQuery solutions.

This is just winging it based on my comment above:
$('input').on('keyup',function(e){
if(e.keyCode === 9) {
var $this = $(this);
// (do your scroll thing here
// ..., function(){
$this.parent().next().find('input').focus();
// });
}
});
Long as the callback timing is correct, this will only change focus after you have already scrolled. You'll need to do your own magic to determine what to scroll to, but this should give you the focus behavior you want.

Turns out you can't smooth scroll for focus changes as the events happen in the wrong order. You get an awful delay while it scrolls the field into view, before focus is set. A better move of the item onscreen, or superfast scroll, is all we can hope for.
As suggested by PlantTheIdea (+1'ed), you need to catch the TAB key and find the next focusable item, bring it into view, then set focus to it.
In practice there are a number of issues to resolve:
Change of focus occurs on TAB keydown (not keyup).
Only match non-hidden inputs (lots of web apps have hidden fields that will go bang if you try to focus them).
Allow for the selection to tab off the first or last item on the page (otherwise the browser loses the ability to tab to its address bar)
use e.keyCode || e.which to allow for older browsers
catch event at document level to allow for cases of other inputs, outside of the scrolling area, causing it to enter the scrolling area (first or last input).
The final code looks like this:
$(document).on('keydown', ':focus', function (event)
{
if ((event.keyCode || event.which) == 9)
{
var $inputs = $(":input:not(hidden)")
var index = $inputs.index(this);
// Index previous or next input based on the shift key
index += event.shiftKey ? -1 : 1;
// If we are in the range of valid inputs (else browser takes focus)
if (index >= 0 && index < $inputs.length)
{
var $next = $inputs.eq(index);
event.preventDefault();
// Move, not scroll, to the next/prev item....
MoveIntoView($next);
$next.focus();
return false;
}
}
});

Related

Disable mobile browser swipe to go back behavior?

I'm building a feature that let's users drag different items around. However, when they drag an item that's near the edge of the screen of their phone, the browser goes back to the last page. Does anyone know if it's able to disable this in a single <div> or is it impossible?
You could try the below code to prevent this.
If the touch element is the targeted div then prevent the action otherwise allow.
HTML:
<div id="tragetDiv"> </div>
window.addEventListener("touchmove", function(event) {
let target = event.target;
if (target.id === "tragetDiv") {
event.preventDefault();
}
});
you can set the draggable item's position inside the div coordinates. If it goes beyond target div simply set the bounds value to that.

JavaScript - JQuery - focus() method - infinite loop

I'm trying to build a functionality that allows keyboard tabbing between two buttons (CodePen below). More specifically I would like the user to be able to tab onto "button1" and on tab, jump to "button2" and then on tab jump back to button 1.
My solution is to put an event listener on "button1" and listen for a tab keyboard event. When that is triggered, use JQuery's focus() method to shift focus to "button2". On "button2" there is an identical listener that listens for tab event and shift focus back to "button1".
The problem is that when I tab onto "button1", the listener records focus and tab event and shift focus onto "button2" which in turn records focus and tab event and shift it back to "button1" again, creating an infinite loop.
Could I please get suggestions in how to solve this problem?
The real world application of this would be to restrict tabbing within a specific module or section of a page.
Thanks!
Steve
https://codepen.io/steveliu7/pen/WOoMJY
var $button1 = $('.b1');
var $button2 = $('.b2');
var checkButton = function(event) {
if ($button1.is(':focus') && event.which === 9){
console.log($(this))
$('.b2').focus();
return;
};
if ($button2.is(':focus') && event.which === 9){
console.log($(this))
$('.b1').focus();
return;
};
}
$('button').on('keydown', checkButton);
You want to restrict tab navigation between two buttons.
Note that it won't restrict screenreaders navigation to those two buttons.
You have to consider TAB navigation but also SHIFT+TAB navigation
On a purely technical point of view event.preventDefault() is what your are searching for:
var checkButton = function(event) {
if (event.which === 9) {
if ($button1.is(':focus')) {
$button2.focus();
event.preventDefault();
} else if ($button2.is(':focus')){
$button1.focus();
event.preventDefault();
}
}
}
I think what you are trying to do can be achieved much easier with the tabindex property in HTML. If you want to restrict tabbing to certain elements only, you can set tabindex="-1" for those elements that you do not want focused.
Source: https://www.w3schools.com/tags/att_global_tabindex.asp

prevent "up arrow" key reseting cursor position within textbox

I recently added some predictive text input fields to the web-app I am supporting.
Big deal, right? Not really, seems like if your web-app doesn't do this -- you are already behind the times and your end-users are complaining. (At least that's how it is over here).
So, my question has to do with the "up" arrow key.
The predictive textbox has a onkeyup listener.
The handler segregates the key strokes and does something depending on the character the user entered.
The up arrow key allows the user to navigate in a div I created loaded with "suggestions."
I have several variables tracking indexes, etc...
Basically, when the user hits the up arrow I will change the id of the div to an id that has some css associated with it that will make the div appear as though it is selected. Additionally I will grab the value in that div and assign it to the textbox where the user is able to type.
The problem is an aesthetic one. Inherently with all text boxes I am learning, the up arrow key will reset the cursor position. This is happening just before I am writing the new value to the text field.
So, on each up arrow stroke, the user is seeing a jumping cursor in the textbox (it will jump to the beginning and immediately it will appear at the end).
Here's the code -
if (event.keyCode === 38 && currentUserInput.length > 0) {
// user has toggled out of the text input field, save their typing thus far
if (currentToggledIndex == -1) {
currentToggledIndex = autoFillKeywordsList.length-1;
savedKeywordUserInput = currentUserInput;
}
else {
// revert currently selected index back to its original id
document.getElementById("kw_selected").id = "kw_" + currentToggledIndex ;
// user has toggled back into user input field
if (currentToggledIndex == 0) {
currentToggledIndex = -1;
}
// user has toggled to the next suggestion
else {
currentToggledIndex--;
}
}
// 2. Determine next action based on the updated currentToggledIndex position
// revert the user input field back to what the user had typed prior to
// toggling out of the field
if (currentToggledIndex == -1) {
element.value = savedKeywordUserInput;
}
// mark the toggled index/keyword suggestion as "selected" and copy
// its value into the text field
else {
document.getElementById("kw_"+currentToggledIndex).id = "kw_selected";
element.value = autoFillKeywordsList[currentToggledIndex];
}
// 3. Determine what the user can do based on the current value currently
// selected/displayed
displayAppropriateButtonActions(element.value);
}
The funny thing is - the "down" arrow works perfectly since by default the down arrow key will place the cursor at the end of the string currently located in the textbox.
Ok, so things that I have already tried -
event.preventDefault();
event.stopPropogation();
I also tried to set the cursor position PRIOR to setting the new value to no avail using a setCursorPosition function I found on another post here. (Yeah, I was reaching with this one)
I tagged this as JavaScript and Jquery. I prefer to use JavaScript, but open to suggestions in Jquery too!
As Ryan suggested. how I achieved this in angular 4.x is
.html
<.. (keydown)="keyDownEvent($event)" >
.ts
keyDownEvent(event: any){
if (event.keyCode === 38 && event.key == "ArrowUp")
{
event.preventDefault();
//logic..
}
I think what you can do is when they move the cursor, grab that and find out what element it is ... then store it in a variable and focus() it and erase it and then put the value you stored back into it.
var holdme = $("#myelement").val();
$("#myelement").focus().val('').val(holdme);
This works for me when having weird cursor issues in jquery/javascript most of the time. Give it a try and if it doesn't work, let me know and I'll see what else might be wrong.
I found that it worked well to capture the caret position, blur, restore the caret position, then focus again.
myTextInput.onkeydown = function(e){
//some other code
if(e.key == "ArrowDown" || e.key == 40 || e.key == "ArrowUp" || e.key == 38){
var caretPos = this.selectionStart;
//do your stuff with up and down arrows
e.preventDefault();
this.blur();
this.selectionStart = caretPos;
this.selectionEnd = caretPos;
this.focus();
}
}
The caret will very briefly disappear, but I think you have to be incredibly observant to notice.

Detecting when an element is about to get focus

I have an ASP.NET page with a Telerik RadEditor (rich text box). When tabbing through a page, when a user gets to the text box, focus gets set to the various toolbar icons before it goes to the textarea. I added some jQuery to one page to set the focus on the text area when tabbing out of the last cell on a form:
$('input[type=text][id*=tbCost]').keydown(function (e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) { //If TAB key was pressed
e.preventDefault();
var editor = $('body').find("<%=RadEditor1.ClientID%>"); //get a reference to RadEditor client object
editor.setFocus(); //set the focus on the the editor
}
});
I am looking for a way to implement this functionality in the control so that it will work regardless of the page it is on. For example, in the above code, focus is only set if the user is tabbing out of the tbCost cell. I would like to be able to set the focus to the text area when a user tabs into the toolbar items.
Is there any way to detect when an element is about to get focus? I know I can see if an element has focus, but I can't think of a way to implement this functionality.
Thanks
Solution:
If anybody has this same question in the future and wants an example, here is the code I used:
$(document).ready(function () {
$('.reToolCell').focusin(function () {
var editor = $('body').find("<%=RadEditor1.ClientID%>");
editor.setFocus();
});
});
You might consider binding to a focus on the toolbar icons and redirecting focus to the text area. Although this might have unintended side effects if users are trying to tab-focus these tools in order to use them.
//on focus eventHandler for all your icons that calls a function
#('.elementtype, class or a generic way of identifying the icons'.onfocus(myFunction(this))
//the function take a parameter of your element, moves to the next sibling element and sets the focus
myFunction = (element) {
element.next().focus();
}

How to set the focus on a javascript modal window?

Our website involves some javascript that produces overlay modal windows.
There is one accessibility problem with this though, once the modal is triggered, the focus is still on the trigger element and not on the modal itself.
These modals can include all sorts of html elements, headings, paragraphs and form controls. What I would like is the focus to begin on the first element within the modal, so most likely to be a h4 tag.
I have explored using the focus() function however this does not work with a number of html elements.
One thought was to add an empty a tag in the window which could gain the focus, but I am unsure about this method.
very late to the party, but the existing answers do not respect accessibility.
The W3C wiki page on accessible modals offers more insight than what's asked in the OP, the relevant part is having tabindex=-1 on the modal container (which should also have an aria-dialog attribute) so it can get :focus.
This is the most accessible way of setting the focus on the modal, there is also more documentation about keeping it in the modal only - and returning it to the element that triggered the modal - quite a lot to be explained here, so I suggest anyone interested to check the link above.
You can append textbox to the beginning of the modal HTML, set focus then hide the textbox. Should have the desired effect as far as I understand your needs.
You could try to blur() the element that has the focus.
to trap focus inside the modal I have used this approach. So the basic idea behind it is exactly to trap the focus in the modal HTML elements and not allowing it to go out of the modal.
// add all the elements inside modal which you want to make focusable
const focusableElements =
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
const modal = document.querySelector('#exampleModal'); // select the modal by it's id
const firstFocusableElement = modal.querySelectorAll(focusableElements)[0]; // get first element to be focused inside modal
const focusableContent = modal.querySelectorAll(focusableElements);
const lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal
document.addEventListener('keydown', function(e) {
let isTabPressed = e.key === 'Tab' || e.keyCode === 9;
if (!isTabPressed) {
return;
}
if (e.shiftKey) { // if shift key pressed for shift + tab combination
if (document.activeElement === firstFocusableElement) {
lastFocusableElement.focus(); // add focus for the last focusable element
e.preventDefault();
}
} else { // if tab key is pressed
if (document.activeElement === lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab
firstFocusableElement.focus(); // add focus for the first focusable element
e.preventDefault();
}
}
});
firstFocusableElement.focus();
you can find it here trap focus inside the modal

Categories

Resources