Adding role="listitem" out of role="listbox" - html

While working on updating a webpage, I have a control that is basically a multiselect control, looks like the below image.
Once the user sets focus on the textbox (the one with purple border, the box below gets visible, wherein on check of the items, the same gets appended to the above text box.
Question:
My question is more from the Accessibility perspective. To allow assistive technologies to read (narrator) this control properly. I am using role="listbox" to the text box and role='listitem' to each of the checkboxes, which I understand it wrong way since listitem should be added as direct child to listbox. But in my case it is not possible.
Is there any way I can link up the textbox and checkbox list and make narrator to treat them as a single control?
<div class='multiselect_wrapper'>
<input type="text" role='listbox' aria-multiselecttable='true' />
<div class="chkList">
<fieldset>
<div>
<label role="listitem" for='chk1'>
<input type='checkbox' id='chk1'>Pizza
</label>
<label role="listitem" for='chk2'>
<input type='checkbox' id='chk2'>Lemonade
</label>
<label role="listitem" for='chk3'>
<input type='checkbox' id='chk3'>Fruit Salad
</label>
</div>
</fieldset>
</div>
</div>

Here's a quick example of a very simple checkbox list:
codepen .io /anon/pen/eboEVB
This is just a quite incomplete example. Do inspire from it, but don't copy-paste it as is.
A few points of attention:
As you have effectively mentionned, the items having role=listitem must be child of the element with role=listbox. This is an obligation, meaning that you have no choice but leave the textbox apar if you want to have correct and accessible code.
If you set role=listitem to the checkboxes, it will override the default implicit role=checkbox. The consequence are that the screen reader won't see them as checkboxes anymore, and thus will keep reading their labels but no longer their state (checked or unchecked). You must set the role=listitem to another element for which there is no default implicit role, such as the divs used in the example
Note how the focus is given to checkboxes rather than to listitems. In this way, we obtain for free normal keyboard processing (i.e. spacebar toggles), as well as the default behavior screen reader have with checkboxes (i.e. announce label and state + help like "press spacebar to change state")
You are recommanded to set the attributes aria-posinset and aria-size to each item, otherwise the screen reader might not see your listbox as such
Set tabindex=-1 in all the items except the currently selected one, which must have tabindex=0. Usually in listboxes, the keyboard user don't tab on each item, and use arrow keys to go from one item to another once they are in the list box. The example is incomplete, it would be nice to support home, end, page up and page down as well.
Don't forget to keep the aria-descendant attribute of the listbox in sync with selection changes. This is important because screen readers use it to tell which item is currently selected
Edit: I'm unable to post my HTML+js code, please help!
I'm trying to post a link to codepen but it is refused. The code is quite long but anyway, if I post it indented with 4 spaces (using Ctrl+K), it is still interpreted instead of just be shown.

Related

ARIA for Elements Without Focus

I'm struggling to enable proper ARIA support for this case. I have a input field which works like a filter, and a set of elements which will be filtered by this input field. The focus is always on the input field, and with arrow up and down you can navigate through the result set. The input needs constant focus because whenever I start typing again, the input should be updated and filter the result set.
Now I want that my screen reader reads the name of the elements when I navigate through the result set. But if I press arrow down (or up) the reader repeats the full part of the input field.
Hint: The result set contains images and text and will open the element in a new view when it is clicked.
<input ng-change="$ctrl.doFilter()" ng-keydown="$ctrl.handleKeydown($event)">
<div class="filter-results" role="list">
<div ng-repeat="item in $ctrl.results track by $index"
ng-class="($index == $ctrl.selectedItem ? 'item-selected' : '')"
ng-click="$ctrl.navigateToSelected()"
ng-mouseover="$ctrl.selectItem($index)"
role="listitem"
<div ng-bind-html="$ctrl.displayName(item)"></div>
</div>
</div>
(shortened example)
HandleKeypress just sets the id of selected item, which will be highlighted by using the proper class.
Is there any solution that screen readers read the name (displayName) of the selected item?
One way to do it, and I'm not advocating this is the best way, but it seems to work, is to have an onkeydown handler for your input field (which you may already have) and when the up/down arrow key is pressed (which it sounds like you're already listening for), you can update a visually hidden <span> (or <div>) that has aria-live set to "polite" and update the text within that <span> with the text of your result item. I think the screen reader will still read the contents of your input field but it should also read the aria-live text too. Maybe not the ideal solution, but you'll get your result item announced.
Some (very) rough code:
<span id="result" aria-live="polite" class="sr-only"></span>
<script>
function mykeydown(e) {
if (e.keyCode == 40)
document.getElementById("result").innerHTML = "whatever is the next result";
}
</script>
Note: You can see the "sr-only" class here - What is sr-only in Bootstrap 3?

Interactive content inside <label> tag in html?

In Mozilla html tutorial it says
Don't place interactive elements such as anchors or buttons inside a label. Doing so will make it difficult for people to activate the form input associated with the label.
Don't
<label for="tac">
<input id="tac" type="checkbox" name="terms-and-conditions">
I agree to the Terms and Conditions
</label>
Do
<label for="tac">
<input id="tac" type="checkbox" name="terms-and-conditions">
I agree to the Terms and Conditions
</label>
<p>
Read our Terms and Conditions
</p>
I tried both and can't find any serious problem with the first usage, what does "make it difficult for people to activate the form input associated with the label" exactly mean?
If you click on the link in the "Don't" example, you'd be taken to that page before you've had a chance to submit the form on the page that link and the checkbox were in. (Though, I guess, technically, you've still managed to activate the checkbox...)
HTML doesn't actually stop you from putting links inside labels though. But it does stop you from putting other form controls inside labels, particularly if they have an ID and the label has a for attribute that's trying to point to another control (since a label can only be associated with one control at a time).
In a nutshell, click in the label associated with a checkbox or radio button. By adding a link the behavior becomes inconstant, clicking part of the label does one thing, yet does something different on another.
On a side note, labels associated with other fields also perform a function. Clicking on those labels bring focus to the associated field.
The general rule of thumb is that interactive elements should not be nested. In this instance the label can be considered an interactive field (though a special case is where the label encapsulates the associated element).

How to set the focus on text (no form)

I know about HTML5's autofocus attribute, but AFAIK it only applies to input tags.
Is there a way to set the focus automatically (and preferably without JS) on, say, a scrollable div with text, so that the viewer can immediately scroll using keyboard ? Or would it be browser-specific ?
I can't find useful ressources online so I'm wondering if "focus" if the right word.
<div tabindex='0'>
this will receive the focus immediately
</div>
tabindex="0"
The tabindex value can allow for some interesting behaviour.
If given a value of "-1", the element can't be tabbed to but focus
can be given to the element programmatically (using element.focus()).
If given a value of 0, the element can be focused via the keyboard
and falls into the tabbing flow of the document.
Values greater than 0 create a priority level with 1 being the most
important.
For more info you can look at the following link http://snook.ca/archives/accessibility_and_usability/elements_focusable_with_tabindex
UPDATE
The other option is to try something like this.
Add the following code to the body tag, substituting the form and field names for your own:
<body OnLoad="document.myform.mytextfield.focus();">
<form name="myform">
<input type="text" name="mytextfield">
<button type="button" onclick="javascript:alert('testing')" name="myButton">Click Me!</button>
</form>

Form enter key action with lists and AngularJS

In my AngularJS project I have an account details page where you can change your personal account information. This page allows for multiple phone numbers and e-mailaddresses to be supplied. Using mouse input (or tabbing to buttons and pressing them with space bar) works perfectly, however I'd like to add the convenience of the enter key pressing the 'logical' buttons.
My form looks like (accidentally forgot to translate a few items):
A simplified version of the HTML for the form can be found on PasteBin, I've mainly removed the directives for managing the lists.
All buttons are <button> elements except for the cancel button which an <a> to the previous page, and the submit button is <button type="submit">.
When selecting any text box and pressing enter, the first (non-disabled) <button> element is 'clicked'. Meaning if I would change the last name, hit enter, the first phone number would be removed.
When you're in a new entry of phone numbers or e-mailaddresses (the row with the green + button) it should click that button, and if it's disabled do nothing.
When you're in any other text box on the form it should hit the save button, and also if the save button's disabled, do nothing.
Both buttons will be disabled based on form validation.
There'd be no trouble in changing the type of a button from button to submit if that'd help.
I would preferably have an all HTML solution, using just semantics, but I doubt that's really possible. So the logical alternative would be to use an AngularJS directive.
Please do not provide a jQuery or plain JavaScript solution relying on IDs or something like that. I don't want to hack my way around AngularJS, rather embrace it.
In the meantime I've worked on a directive that allows me to declare what I've called 'submit scopes'.
In essence you have actions (inputs) and targets (buttons), they're bound through a service by a key you can assign in the template. To avoid keys from clashing and from simple annoying work you can create a submit-scope which will cause it's children to prepend a unique key to the value they're accessing.
Within a submit-scope you can still override an action to use a global key instead by setting the attribute global-submit="true".
Example code:
<div submit-scope>
<input type="text" submit-action />
<button type="button" submit-target>Pressing enter in the above field will click this button.</button>
</div>
You can view the entire source code and a slightly larger example on Plnkr.
I just tried to replace
<button>Cancel</button>
with
<input type="button" value="Cancel">
and it seems to work correctly...

Is it possible to use an input within a <label> field?

I have a bunch of optional "write-in" values for a survey I'm working on.
These are basically a radio button with a textbox within the answer field - the idea being that you would toggle the button and write something into the box.
What I'd like to do is have the radio button toggled whenever a user clicks in the text field - this seems like a use-case that makes a lot of sense.
Doing this:
<input type="radio" id="radiobutton"><label for="radiobutton">Other: <input type="text" id="radiobutton_other"></label>
works fine in Chrome (and I am guessing, other WebKit browsers as well), but there are weird selection issues in Firefox, so I'm assuming its a non-standard practice that I should stay away from.
Is there a way to replicate this functionality without using JavaScript? I have an onclick function that will work, but we're trying to make our site usable for people who might have NoScript-type stuff running.
Putting an input inside a label actually has a slightly different meaning. It doesn't make the input itself a label, it implicitly associates the label with the input in the same way as if they were linked by a for/id.
However, this only happens when the label doesn't already have a for attribute to override that (see HTML4 s17.9: “When present, the value of this attribute must be the same as the value of the id attribute of some other control in the same document. When absent, the label being defined is associated with the element's contents.”). It is unclear according to spec what should happen when both containment and for are present.
(And also it doesn't work in IE, which makes the point moot in practical terms.)
No, you'll need some scripting for this.
<input type="radio" id="radiobutton">
<label for="radiobutton_other">Other:</label>
<input type="text" id="radiobutton_other">
<script type="text/javascript">
var other= document.getElementById('radiobutton_other');
other.onchange=other.onkeyup= function() {
if (this.value!=='')
document.getElementById('radiobutton').checked= true;
};
</script>
It (an input inside a label) validates just fine as HTML 4.01. One potential issue I can see with your code is that both radio elements have the same ID in your example. Element IDs must be unique in HTML and XHTML documents and you should use the name attribute instead to identify a radio group.
If you are still having trouble after changing this, you will have to move the input outside of the <label> element and use scripting.