Focus blur on client routing ideal for SPAs? - javascript

I have a single page application. There is a page with products and on the bottom a link to go to the next page. Upon clicking this "next" link the list of products in the DOM is replaced. While the link clicked has stayed the same and maintains focus from the click. Is it better for me to do something like document.activeElement.blur() is that case? Or should I just leave focus on that as is?
I'm unsure what best practice is as with normal server routed pages the focus would be reset with the page load. But I haven't seen any information indicating manually resetting focus on client routing would be the best experience from an accessibility point of view.

Never ever use blur. It's just bad, random and possibly frustrating.
IN a native application, you should always exactly know where the focus is, and the focus should always be at a precise place; otherwise keyboard accessibility is broken.
If you consider your web application as being a true application, you should observe the same rigour.
So, never use blur, since you don't know at all where the focus is going to move afterwards. If you are going to remove something from the DOM that currently has focus, you should first place it in another place that make sense.
IN your case: clicking on a link, you have two reasonable options:
Leave the focus on the link (reasonable as long as you don't move, hide or remove it from the DOM)
Move the focus at the beginning of the new content that just appeared / has just been replaced
You may ask users of your application which solution they think is the best, or deduce the answer by observing them during a test session.
Let's summarize quickly: whether you are making an old-style website with different pages, and you don't have to matter much about focus, or you are making a real application and in that case you should be as rigourous as if you were developing a native app.
Terribly simple.

Related

How do I locate the function that is stealing DOM focus?

I'm trying to debug the integration between my app and Stripe's Elements component library. Everything works fine in sandbox mode, but we ran into a problem on production in the 3D Secure authentication process. This involves loading an iframe, into our app, that contains a form from the credit card's issuer (usually via a technology partner, like Arcot).
The form loads correctly and its buttons are working as expected, but the element (for a SMS one time code) is not behaving. Every time I click on the input, something is immediately pushing the focus back to the element of the iframe. This makes it impossible to type anything in, since by the time I touch a key, the input is not in focus. For reference, it is possible to change the input's value using document.getElementById('enterPIN').value = '123456';
I'm not sure if my app is triggering focus() calls (I don't think so) or if it is some part of the iframe code or even Stripe's. Is there a good way to monitor DOM events and do a stack trace for the trigger of each one?
I tried two tactics. Neither gave an obvious answer, but they did point my search in the right direction.
I opened the Event Listeners panel (in the Elements tab of my browser's developer tools) and removed everything I could find, but it seems that this doesn't actually change the behavior of the page- focus kept being stolen away. Luckily, I also noticed some listeners that were defined by the Material UI library.
I used monitorEvents() to get a few more details, but the src & target values were not much help and event.relatedTarget was always null.
In the end, I found this discussion and realized that my MUI Dialog component was stealing focus whenever I clicked on the iframe triggered by its content. This was easily fixed by adding the disableEnforceFocus attribute.

Close popup/dropdown on focusout (keyboard control)

I'm trying to make an accessible popup/dropdown like the example on W3's website. If you click on the keyboard users approach 1 menu, and then tab into the Space Bears menu item, pressing enter will open the menu. Then, if you press tab, you go through the menu. Once the focus is out of the menu, the dropdown automatically disappears. This is the functionality that I'm trying to emulate. I got the rest working, but their JavaScript snippet doesn't explain how to hide the popup on focusout.
I got the following solution of my own, which uses a timeout. The timeout is there, because without it, the activeElement is the body. I need to wait that short bit for the focus to be on an element. I feel like there could be a more reliable approach, rather than relying on a timeout, though.
Note that I called it a modal in my code, but it's likely not actually a "modal". This was just what I named it.
$('.js-modal *').on('focusout', function() {
setTimeout(function() {
var is_in_modal = $(document.activeElement).closest('.js-modal').length;
if (!is_in_modal) {
close_modals();
}
}, 10);
});
Your idea of something that disappears automatically when you go out of it is a bad idea.
You'd better switch to a more classic solution, like a true modal, as already well described by the other answer.
It's a bad idea because it's confusing.
Let's imagine this scenario: we have five elements 1, 2, 3, 4 and 5. 3 and 4 are initially hidden and appear when 2 is focused.
I'm initially on element 1:
I press tab and go to element 2. Element 3 and 4 appear, but since I'm blind, I may not have noticed it at all.
I press tab again. I go to element 3
I press tab. I go to element 4
I press again tab. I go to element 5. Elements 3 and 4 disappear but again, I may not have noticed it.
OK, well, I finally want to go back to element 3, so I press Shift+Tabb. I expect to land on element 4, but went on 2 instead. Where is element 3 ?
I hope that with this little scenario, you understand the problem. If I'm not aware at all that elements appear or disappear, I find elements in a different order than I expect.
If at that moment I don't understand the logic and don't find back the element 3, great are the chances that I leave the site forever.
You aren't convainced ?
I imagine you have been told to do that to have the same logic for keyboard users than with mouse users.
With the mouse, you click on the menu, it opens, but closes as soon as you leave its area.
Note that it's also a poor idea in terms of accessibility, because you require the user to be quite precise. Following precise paths with the mouse isn't' always easy, especially for elder people or people with movement difficulties.
For that reason, we usually recommand to no longer use menus like that, and change their behavior to make them disappear only when clicking outside of it. So, mouse users with some movement difficulties have all their time and freedom to select what they want to select.
For keyboard users, that's kind of the same thing. If I'm blind, I expect focusable elements to always have the same tab order, and expect changes in that order only when I make a conscient action like press enter to expand/collapse a menu.
If I'm sighted and use the keyboard for whatever reason, I don't expect elements to appear or disappear on screen when just pressing tab.
Still not convainced ?
So ask yourself another question: how do I use your interface with a smarphone ?
With a touch device, there's no real focus, as well as there's no real mouseover, until you click on a precise element to interact with it. It's problematic, isn't it ?
You don't have at all these notions, so you must react on clicks. You don't have choice, and that's good.
automatically disappears when the users uses keyboard/TAB navigation to focus out of it.
This is the exact opposite of the behaviour of a modal.
You should trap focus inside your modal and it should close with the Esc key and via a close button (accessible via keyboard).
This article is a good starting place to learn about Modals, although I disagree with the method for point 5 "While Open, Prevent Tabbing to Outside the Dialog" - this should also include using aria-hidden on every element outside the modal as otherwise screen reader users can end up outside the modal (as they may navigate via links or headings etc.) when they shouldn't be.
Final thought - are you sure you need a modal? There may be a better pattern you could use if the above does not apply to your use case.

Notify screen reader a page changed [duplicate]

Imagine you have a simple, single-page application - regardless of whether it was written using Backbone, Angular, Ember or anything else.
How can you tell a screen reader that we've changed 'page' when a route is followed?
In a classic application, when I navigate from /index.html to /about.html the screen reader obviously detects the page change, and re-reads as you'd expect.
In my Backbone application though, when I follow a route I cannot work out how to trigger a 're-read'. I've tried triggering a focus event which I'd seen somewhere, but that doesn't seem to work.
Note: I'm currently testing with NVDA/Chrome.
Overall, you should not need to trigger a 're-read', and depending on your UI that might not be a good thing anyway.
My experience has been with angular.js (as an accessibility person rather than the developer), and our overall approach was to manage the focus rather than trigger a re-read. (We do extensive accessibility testing.)
The key thing from a UI point of view (primarily for screen reader users) is that selecting a link (e.g. about.html) should take you somewhere.
In this case the appropriate place to put the focus would be the top of the content area of the about 'page', hopefully an <h1>.
In order for that to work the target element should be focusable via a script, so probably needs tabindex unless it is a link or form control:
<h1 id="test" tabindex="-1">
The -1 means it is not in the default tab order, but is focusable via a script. See more at WAI-ARIA authoring practices.
Then at the end of the function that loads the new content, including the tabindex attribute, add something like:
$('#test').attr('tabindex', '-1').css('outline', 'none');
$('#test').focus();
When adding tabindex dynamically it is best to do so in a line before the focus() function otherwise it may not work (I remember that from testing with JAWS).
To test this I would use either:
NVDA & Firefox, Windows
Jaws & IE, Windows
It is also good to test with VoiceOver on Safari/OSX, but that works differently and may not hit the same issues as a windows based screen reader.
You will hit a lot of issues with Chrome/NVDA as that is not supported very well, and end-users are very unlikely to use that. IE is ok with NVDA, but Firefox is best.
Overall, it is worth getting to know the WAI-ARIA authoring practices, particularly Using ARIA in HTML. Even though you are using a JS app, the browser (and therefore screen reader) is interpreting the resulting HTML so that advice is still relevant.
Lastly, if you are updating page content without the user pressing space/enter to activate something, you might find that JAWS/NVDA do not know about the new content as their 'virtual buffer' has not updated. In that case, you might need to add a JS shim to make them update, but only do that if you run into problems in testing, it should not be a global patch.
Taking the answer from #AlastairC, and the comments below it. I've taken this a bit further now and am going with this as my solution going forward:
My go-forward solution
I found that just reading out the first heading wasn't really that useful. Especially if the last page you were on was a loading sequence. You can hear that there something new has been focused, but it's certainly not clear that this forms the part of a whole now page.
Add some useful, descriptive text to the page
As such I now have a single paragraph at the top of my page layout template. This includes a screen-reader friendly message, along with a very rough overview of what the page.
<p class="screenreader-summary" tabindex="-1">
The <strong>Dashboard</strong> page is now on-screen.
It contains several widgets for summarizing your data.
</p>
Note that the tabindex value allows us to focus this element with JavaScript. You might not want to use a p element for this, you can use anything you like really.
Hide it off-screen (optional, only required if it would break your design/readability)
This is then coupled with CSS to move this element off-screen:
.screenreader-summary {
position: absolute;
left:-10000px;
top:auto;
width:1px;
height:1px;
overflow:hidden;
outline: none; /* Important, don't show an outline on-focus */
}
Focus this element, when a new page is shown on-screen
Finally, in the JavaScript code that shows your page on screen (e.g. in MarionetteJS using onShow or the show event):
$yourViewEl.find('.screenreader-summary').focus();
The result
I'm a sighted person, so take what I say with a pinch of salt - however I found that reading out a short description is so much more useful.
For angular the url changes, If someone REALLY needs to reread everything, (like me because of requirements), what did the trick for us was this:
$(window).on('hashchange', function () {
location.reload();
});
and we just added extra code to handle pages like "success" were no reloads are supposed to happen.
this simulates the actual page loading, and screen readers will read it normally like a page change.
kind of defeats the purpose of angular in a way, but this will help people like me who already have the application, and want a quick fix.

Hashchange not firing when user clicks on same link

I'm creating an HTML and Javascript client for running in browser which talks to REST API. I'm using RouteMap to set my URLs. So I've kept a convention something like this
http://mysite.com/#/{ResourceName}/[edit|view|list]/[Id]/
I've set just one route and I'm grabbing these parameters in the function bounded to hashchange. Most of the things work fine. Just two issues and I'm stuck because of them.
If the user clicks on the same link twice, hashchange event doesn't fire. Yes, hash has not changed so obviously it won't fire. But there should be something which can be done and I'm missing that.
If I change something in the UI (like bring up new divs and hide some) for which I don't want to change the hash link, I loose that history and can't go back by clicking the back button properly.
Any help will be grateful.
For #1, you probably want to attach a handler to the link click event. That way you can tell if the link is being clicked. When I use onhashchange, I always attach something to the click event to assist polyfills for onhashchange, so at least I can tell when it's failing.
For #2, I want to point out that having automatic stuff change the user's history is problematic. You could fill someone's history with minute, meaningless hash changes. I recommend only changing the history when the user actually interacts. Short of that, HTML5 does offer pushState and popState. Reference

javascript events and html

Could you suggest the best way to keep focus on a particular input field on page?
What I am trying to say is, no matter where user clicks on the screen, the focus should return back to this one particular input.
I am thinking of a timer function that would check for focus every 500ms and if its not there, then bring it back.
Also the best way to submit this input field without making use of any button
Any other and best solution for this?
Even if I don't like the idea, thinking about usability and user experience. Anyway, to answer your question, your best shot probably is to set the focus initially to that input element and watch for the
blur event. Addionally you might want to check for outside click events.
That might look like this:
$('#test').bind('focusout', function(e) {
if($(this).val() !== 'releaseme') {
setTimeout(function() {
$(e.target).focus();
}, 25);
}
});
That would force the focus to that input (with the ID "test") 25ms after it lost the focus. To check for the additional outside-click check this link.
Example link: http://www.jsfiddle.net/FX79h/
Again, this sounds not usefriendly. You might want to think about whatever you are trying to do.
Would be a major impediment to disabled accessibility consideration. Remember, some people don't use mice to navigate, and you'd render the site useless to them.
As to allowing submit, you could trap the enter keystroke via Javascript...there's several tutorials on how to do it. However, this would also negatively affect the expected user interaction pattern and disrupt accessibility aids. The button text is the only thing telling a blind user's screen reader that they can submit to the site. Without it, your site is a black hole to them.
I'm all for experimentation and pushing the envelope, but there are reasons that you see so many common elements across the web. Think about it like this--would you stop for a triangular blue stopsign? How about a square pink one? Believe it or not, familiar patterns make for a more comfortable experience. How you "push" familiarity is what determines your success as a UI person. I might add that there's a LOT of bad UI out there....

Categories

Resources