self disable button, accessibility - html

is there a way to don't read 'unavailable' or 'dimmed' in a self-disable-button?
See the example Example
var saveBtn = document.getElementById("saveBtn");
var helper = document.getElementById("helper");
var content = document.getElementById("content");
saveBtn.onclick = function(e) {
saveBtn.setAttribute("disabled", "disabled");
saveBtn.setAttribute("aria-disabled", true);
content.innerHTML = 'Lorem input a lot of stuffs';
helper.innerHTML = "Content added, please read it";
setTimeout(function(){
helper.innerHTML = "";
saveBtn.removeAttribute("disabled");
saveBtn.setAttribute("aria-disabled", false);
}, 5000);
};
Voice only says: 'Content added, please read it'
NVDA says: 'Content added, please read it. Unavailable'
I know that it is happening because the button still having focus. But, I need to find a solution for that because I can't modify the current behavior of my page.
I'm using the html helper to inform transitions as you can see https://stackoverflow.com/a/38137593/3438124.
Sorry for ugly code, this is only to simulate my real behavior.
Thank you guys!

You will need to move focus to the new element. Give it tabindex=0 and then use focus().
aria-live is for when you want to have the screen reader speak changes for the content area with the aria-live attribute. Since you use it on a sibling div, you are missing the opportunity for it to just do what it does. Alternative, you can skip the tabindex/focus() approach and just put aria-live on a container for your new content.
Also, you can ditch the aria-disabled and just lean on disabled for the button. aria-disabled is for elements that otherwise do not support disabled.

You answered your own question when you said "I know that it is happening because the button still having focus" and then aardrian pointed it out explicitly when he said "You will need to move focus to the new element".
Keep in mind, though, that whether the focus remains on a disabled object is totally up to the user agent (browser). Some browsers leave the focus on the disabled object and others move it to the parent.
aardrian's comment about using tabindex was if you wanted to move the focus to an object that is not normally focusable (ie, if it's an element you can't normally TAB to). So if you want to move the focus to some simple text (just to get it off the button), then I'd tweak aardrian's suggestion and use tabindex='-1' instead of tabindex='0'. That will allow you to call focus() on that element but won't allow the user to TAB to it.
If you want to move the focus to another button on the page, or some other element that can naturally receive focus (checkbox, input field, etc), then you don't need tabindex.
If you end up moving the focus to the text that was just added, then you don't really need aria-live because the screen reader will read the text that you just focused to. But that's only relative to the example you posted, which I understand is just a sample to show the problem. Your real app might not be adding text.
And I want to second aardrian's recommendation of not setting aria-disabled when you're already using the disabled property. It's superfluous. The aria-disabled property is for when you're simulating a disabled object.

How the text is read varies reader to reader. None is right or wrong. If you want the text being read out to be same and consistent across the readers..Do a little workaround. Add an aria-label="desired text" to your button. This will override anything that is present inside the button tag.
eg
<button aria-label="desired text button">This text will be ignored</button>
Nvda will read the button as "desired text button". Text inside button is ignored. Now you can handle(add/remove) the disabled and aria-label attribute with JS.
In the context of your question you can try:
Instead of:
helper.innerHTML = "Content added, please read it";
Try using:
saveBtn.setAttribute("aria-label", "Content added, please read it.");
setTimeout(function(){
saveBtn.removeAttribute("aria-label");}, 5000);
Then the text will be same across the readers.

Related

Announce aria-live text change despite div being hidden

I have a div with an icon and a message which is hidden unless someone mouses over it, that does an action when clicked.
For sighted users, the icon switches to a check mark when clicked, and the message is changed when the icon is hovered over. For users that use the tab button however, the message isn't displayed.
The div with the message is an aria-live region, but since it is hidden, the screen reader will not announce the new message. Is there a way to announce the message despite the region being hidden?
The short answer is no. an aria-live region must be visible if you want its content changes to be announced.
You may read this question where I give a small trick: show the element a few seconds, long enough to let the screen reader read the message, and then hide again.
However you must show the message at least for 3-5 seconds because some screen readers cut of before the end if you hide the element while it is still being spoken.
IF showing the message for that long is unacceptable, you can still put it off-screen, by using a little CSS like below.
Note that many frameworks already have classes like .visually-hidden, .sr-only, etc. with a similar code. If you are using one of them, use what they define.
.visually-hidden {
top:0;
left:-2px;
width:1px;
height:1px;
position:absolute;
overflow:hidden;
}
```
I've found a better way to handle this issue. First you'll have to always set your live element visibile in DOM, not UI, and after that, you'll need to update the textContent, or innerHTML; next step, just setTimeout for a couple of milliseconds (100ms in my case) or more, and after that just clear the contents inside. In this way the screen reader will still read the previous message entirely. You can also clearTimeout if new messages has to be appended in the meantime.
example:
function updateLiveRegion(message) {
const elem = document.getElementById("my-id");
elem.textContent = message;
clearTimeout(myTimeout);
myTimeout = setTimeout(() => {
elem.textContent = "";
} , 1000);
}
updateLiveRegion("my message");

Is there a way to inform the screen reader about a transition to a new section on the same page?

I have a page that has 2 steps to register a user.
After a user has filled out all fields of the first section, he needs to confirm the "Terms and Conditions" and press a button to confirm it.
After he has pressed the button, first section is becomes readOnly and the second section (more fields to fill) appears at the bottom of the page and the page does a scrollTo this new section.
I need to inform the screen reader that there is a new section on the same page but I don't know who can I do it.
I appreciate your help!
In your html have an empty span/div with aria-live="assertive". In your button click function, add the text you want the reader to announce to that span.
(This is the same function where you will be taking focus to that section.)
Don't forget to empty it outside the function to make it announce properly next time also.
Aria-assertive text will be announced each time it is changed.
Eg.
In HTML
<span id="announce" aria-live="assertive"></span>
<button id="btn">Click</button>
In javascript
$("#btn").click(function(){
$("#announce").text("Scrolled to a new section");
});
This is about focus management. You need somewhere to anchor focus that makes sense to the user and you need to then move that focus.
This is not an ideal solution overall, but lacking context for the larger objective I'll give you the bits to get this part functional / useful.
First, add this style so you can see where the focus is going (you can remove/change it later):
*:focus {
outline: 2px solid #f00;
}
Now as you tab through the page you can see where the focus lives.
Then in your script where you create the new form (I recommend you actually just hide this section and display it instead of writing it in via JS, but I understand this may be a demo), update the <h3> to be focusable by adding an id attribute and then a tabindex so that you can drop focus on it. I use the <h3> you already have since it provides the context for the user and in this case overrides my general distaste for using tabindex on non-interactive elements.
<h3 id="second" tabindex="0">
Then add bit of script after your setTimeout() that moves the focus to that element (thereby ensuring it has been rendered and can receive focus):
var secondForm = document.getElementById('second');
secondForm.focus();
Now when you click the "Continue!" button, the page scrolls and the heading will receive focus, get announced (you can add instruction text, etc), and the user may continue.
You will probably need to massage the script a bit, maybe stuffing it in its own timer function to be certain it only fires when you want, but overall the general concept is in there.
I made a pen to demo it.

How does tab-press work in HTML page

I got some problem when user pressed the TAB-key. There should be a static way in which the user can jump from one form element to the next.
I know there is a posibility to declare in which order the elements should be selected with TabIndex.
Now I would like to know how does the browser decide which element is focused as next Element after pressing Tab.
EDIT: Does it only walk down the dom or does look it on the position on rendered Website, that's what i want to know.
The process of deciding in which order to skip from one focusable element to the next is fairly complex. The first step is to find out, which elements may gain a tab focus.
There is an article by Maks Nemisj that covers your question in length: “Focus, tabIndex and behavior of browsers”.

How to make a custom web component focusable?

I'm writing a custom web component that is meant to be interactive. How can I tell the browser that this custom component should receive focus?
I wish that my custom element…
could be focused (by tab-navigation);
could receive keypresses when focused;
could be matched by :focus pseudo-selector.
I'm not using any external library, just plain HTML5 APIs.
Based on this demo that I found in this question, I have this answer:
Just add the tabindex attribute to the elements you want to be focusable.
// Add this to createdCallback function:
if (!this.hasAttribute('tabindex')) {
// Choose one of the following lines (but not both):
this.setAttribute('tabindex', 0);
this.tabIndex = 0;
}
// The browser automatically syncs tabindex attribute with .tabIndex property.
Clicking on the element will give it focus. Pressing tab will work. Using :focus in CSS will also work. keydown and keyup events work, although keypress doesn't (but it's deprecated anyway). Tested on Chrome 44 and Firefox 40.
Also note that this.tabIndex returns -1 even if the HTML attribute is missing, but this has a different behavior than setting tabindex="1":
<foo></foo>: No tabindex attribute, the element is not focusable.
<foo tabindex="-1"></foo>: The element is not reachable through tab-navigation, but it is still focusable by clicking.
References:
http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
https://github.com/whatwg/html/issues/113
#Denilson, I would like to provide you with some more information.
As you said, this.tabIndex = 0 works when your webcomponent contains no focusable elements. If it does, it gets more complicated.
For example, if your component contains one or more inputs, then first the "whole" component gets focus, and only later, when tabbing, each inner inputs get focus, one by one. This is usually not what you want. Usually, when the component gets focus this should mean its first input gets focus immediately.
Also, there is a reverse tabbing problem. If your first input has focus and you press SHIFT-TAB, then the "whole" component gets focus, and you are forced to press SHIFT-TAB twice to move to the previous element.
I found this to solve all focus and tabbing problems:
// At first, the component may get focus and accept tabbing.
createdCallback = function () { this.tabIndex = 0; }
// When the component gets focus, pass focus to the first inner element.
// Then make tabindex -1 so that the component may still get focus, but does NOT accept tabbing.
focus = function (e) { firstFocusableInnerElement.focus(); this.tabIndex = -1; }
// When we completely left the component, then component may accept tabbing again.
blur = function (e) { this.tabIndex = 0; }
Note: As of now (Sep 2015) if an inner element gets focus, then the "whole" element is not matched by the :focus pseudo-selector (tested only in Chrome). If find this behavior to be just plain wrong. The focus event was fired, and the blur event was not. So the element should have focus, right? I hope they change this in the future.
Short answer: delegatesFocus is what you need here, not tabindex.
Details:
Assuming that you have interactive elements inside the shadow DOM, there is no satisfying way to make the component programmatically focusable with tabindex:
if you set it to 0 you add the host element to the tab sequence ("sequential keyboard navigation") and you have an extra tab stop
if you set it to -1 you remove not only the host element but any interactive element inside its shadow DOM from the tab sequence, so the whole thing becomes inaccessible for keyboard users
There's a web component API just for this: ShadowRoot.delegatesFocus, see here. Set this to true and you'll get:
calling .focus() on the host or clicking on any non focusable part of the component focuses the first focusable element in the shadow DOM
:focus styles are applied to the host in addition to the focused element within
tab sequence is unchanged (it should already work the way you want)
It's supported since shadow DOM v1.
One very pragmatic approach I use, if possible and suitable, is just to put a <button type='button'> around my custom element.
This maybe does not fit as solution for you, I mention it anyway for others stepping into this question / problem.
It handles all focus matters, including a focus rectangle an so on.
To tame a <button> is less work than it seems (think especially about the line-height the button changes)

HTML: Same Page Anchoring and using Tab Key

I am using a link to jump to the content section of the page. It works fine; however, in IE and Chrome, after the jump if I press Tab it goes back to .
link : Skip to Content
Content Location <a id="anchortext" class='hidden'>Content</a>
Any Idea?
I suspect it has to do with the tab indexes of existing html elements on the page - clicking on an anchor tag as the one you specify above will take you down to the relevant section, but then pressing tab will take you to the first available tab stop (usually a link or form input item), which could very easily be back at the top of the page.
If you refresh the page and press tab once, you'll be taken to the first tab index enabled element of the page - I'm guessing that'll probably be the same section you were being taken to in your original question...
This appears to be a matter of different handling of internal links in browsers, and seems to fall into the category of behavior not defined in specifications, hence browser-dependent.
When you have focused on a link (usually, with tabbing) and hit enter to follow the link, browsers may or may not retain the focus. You can see the difference in behavior by using a CSS rule like :focus { background: yellow; }.
If the focus is retained (which is somewhat illogical, as the focused element may well be out of sight), a tab will take you to the next focusable element on the page (“next” in the sense of tabbing order).
If focus is lost, it may be treated as giving focus to the entire page (an IE oddity), or as having no focus. Either way, hitting tab will take you to the first focusable element on the page (as per the tabbing order).
I’m afraid there’s nothing you can do on a page to change this. It’s between the user and the browser.
AFAIK there's no way of doing that using only html.
So, i made a javascript script using jquery.
When the user clicks on the jump item, i look for the next link or the next link inside a specific element and put a focus on it.
This solves my problem with Chrome (>25) and IE (>7) and of course Firefox does the excelent job of interpret the tab action correctly.
$("#jumpToMenu").on("keydown", function(e) {
var keyCode = e.keyCode || e.which;
if(keyCode == 13) {
e.preventDefault();
e.stopPropagation();
$("#myMenuToJump").find('a:first').focus();
}
}).on("click", function(e) {
e.preventDefault();
e.stopPropagation();
$("#myMenuToJump").find('a:first').focus();
});
Hope this helps...