How do I make a VoiceOver on Mac read the aria-label (or another aria- attributes) with no conflict with tabindex?
I am trying to provide some accessibility stuff to a search result page with the structure like this
<div class="header">
<input value="" name="search" type="search"/>
</div>
<div class="main">
<div class="adv-block">
Link to adv 1
Link to adv 2
</div>
<div class="search-result">
Search result 1
Search result 2
</div>
</div>
First, I want a user with tab navigation skip advertisments, so I provide tabindex for and input and then for the search results, like this.
<div class="header">
<input value="" name="search" tabindex="1" type="search"/>
</div>
<div class="main">
<div class="adv-block">
Link to adv 1
Link to adv 2
</div>
<div class="search-result">
Search result 1
Search result 2
</div>
</div>
But then I would like to help screen reading programme (in my case a VoiceOver on Mac) to read the zones correctly. So, I mark the search results contaiter with its role and description.
<div class="header">
<input value="" name="search" tabindex="1" type="search"/>
</div>
<div class="main" role="main" aria-label="Search results">
<div class="adv-block">
Link to adv 1
Link to adv 2
</div>
<div class="search-result">
Search result 1
Search result 2
</div>
</div>
The problem is that VoiceOver also navigates according to tabindex and it goes from the input directly to the first link.
I tried to cheat with adding a tablindex attribute to the container
<div class="header">
<input value="" name="search" tabindex="1" type="search"/>
</div>
<div class="main" role="main" aria-label="Search results" tabindex="2">
<div class="adv-block">
Link to adv 1
Link to adv 2
</div>
<div class="search-result">
Search result 1
Search result 2
</div>
</div>
But this cases changes for a usual tab navigation.
So, is there a way to make VoiceOver read that a user proceeded to a search result zone?
Please be very careful when trying to force a particular navigation style, as tabbing is not the only (or even primary) method of navigating with a screen reader.
Most of the time a screen reader user would use 'browse' navigation to read the content. On VoiceOver this is cntl-alt-right arrow, in Jaws/NVDA it is just down-arrow.
Browse mode will go through all content, not just form controls and links. Browse mode is not affected by tabindex.
The problem with tabindex is that it over-rides the default (code) order, which can be very confusing when it doesn't match the browse order. This is more obvious when there are other things in the page, and then you skip chunks of content and go to the lowest tabindex.
I would recommend something like:
<header role="banner">
<div class="header" role="search">
<label for="search" class="hidden">Search</label>
<input value="" name="search" type="search" id="search">
</div>
</header>
<div class="adv-block">
Link to adv 1
Link to adv 2
</div>
<main role="main" id="main" aria-labelledby="results">
<h1 id="results" class="hidden">Search results</h1>
<div class="search-result">
Search result 1
Search result 2
</div>
</main>
NB: I am assuming there will be other stuff to go into the header, otherwise it wouldn't be worth using the header with banner role.
Typical ways that people using screen readers get to the 'content' are:
Arrow down through everything, time consuming but reliable.
Skip by heading (cntl-alt-cmd-h in VoiceOver), and the main heading 1 is a good indicator of the primary content of the page.
Open the landmarks dialogue (cntl-alt-u and then left/right to find it in VO) and go to the 'main' landmark.
Tabbing through links, and consistency trumps efficiency here.
Overall I would recommend against trying to manipulate the tab-order, and make sure you provide good headings, landmarks, and maybe a skip-link if you really need to provide a short-cut. This applies to Windows based screen readers as well.
The current w3 accessibility standard says to try to avoid using positive tabindex values. It is best practice to layout your dom so that you can simply use tabindex=0 for everything that should be tabbable to.
Related
I have a page structured as following.
<div>
<div>
<h2>header</h2>
<button>close button</button>
</div>
<div>
<div>some info</div>
<div roll='groub' aria-label='some general text about which checkbox is selected'>
<div>
<input type="checkbox" id="scales" name="scales" checked aria-label="scales">
<label for="scales">Scales</label>
</div>
<div>
<input type="checkbox" id="horns" name="horns" aria-label="horns">
<label for="horns">Horns</label>
</div>
</div>
</div>
</div>
I have my screen reader on and want to be able to tab from each ui component, and screen reader reads it out for me as I press tab key.
when it reaches to the div with roll of group, then it reads out the aria label of that div element plus all of its children!
What I want is to read only the aria-label of the div with roll of group and stops. Then only reads the aria label of the checkboxes when I tab into them.
any suggestion on what roll I should define for input elements so they get announced only when they are focused by tab key ?
The question should be how to use groups to build a screen reader friendly form.
When it comes to checkboxes or radio buttons, a group is the correct way to go, as it will bind the overall question to the controls, which are in tab order.
So that would be something like
Close button, button
Tab
some general text about which checkbox is selected, group
Scales, checkbox, unchecked
The group itself will not be focussed. But when focussing the first checkbox, the screen reader will announce the group’s name once. This will help screen reader users choose the right one. Once they change to the next checkbox, the group’s name will not get announced.
This is how it should work, since forms are used mainly by means of Tab and the user needs to get the info about what the checkboxes are about.
To follow the First Rule of Using Aria, you should use a <fieldset> element with a <legend>.
If you can use a native HTML element [HTML51] or attribute with the semantics and behavior you require already built in, […] then do so.
You should not provide aria-label attributes when there is a visual label already. It is correctly used with a for attribute, hence is already providing an accessible name to the checkbox.
<div>
<div>
<h2>header</h2>
<button>close button</button>
</div>
<div>
<div>some info</div>
<fieldset>
<legend>some general text about which checkbox is selected</legend>
<div>
<input type="checkbox" id="scales" name="scales">
<label for="scales">Scales</label>
</div>
<div>
<input type="checkbox" id="horns" name="horns">
<label for="horns">Horns</label>
</div>
</fieldset>
</div>
</div>
I am attempting a dynamic form generator based on Angular's Dynamic Forms template using Angular 7 and I'm running into a css issue. I am using Bootstrap 4.0 and I hope it's not an issue where I need to go back to 3.0 (I had a prior issue that involved that, but correct re-coding got it to work in 4.0). If so, please let me know.
Now, here is the way that my app works correctly for my end product. My code to generate the drop downs is:
<div class="row">
<div *ngFor="let question of questions" class="col-md-6 form-group">
<label for="{{question.key}}">{{question.label}}</label>
<span [ngSwitch]="question.controlType">
<select *ngSwitchCase="'dropdown'"
[id]="question.key"
[formControlName]="question.key"
[className]="question.fieldClass">
<option *ngFor="let opt of question.options" [ngValue]="opt.value">{{opt.name}}</option>
</select>
</span>
<span class="help-block error" *ngIf="isFormTouchedAndInvalid(question.key)">{{question.label}} is invalid</span>
</div>
</div>
When this gets rendered to the screen, the drop downs are aligned correctly, with the correct widths, as you can see:
Now, if I follow Angular's method, my main code block will now become:
<div class="row">
<app-question *ngFor="let question of questions" [question]="question" [form]="form"></app-question>
</div>
And my app-question component has the following code:
<div [formGroup]="form">
<div class="col-{{question.colType}}-{{question.colWidth}} form-group">
<label for="{{question.key}}">{{question.label}}</label>
<span [ngSwitch]="question.controlType">
<select *ngSwitchCase="'dropdown'"
[id]="question.key"
[formControlName]="question.key"
[className]="question.fieldClass"
>
<option *ngFor="let opt of question.options" [ngValue]="opt.value">{{opt.name}}</option>
</select>
</span>
<span class="help-block error" *ngIf="isFormTouchedAndInvalid(question.key)">{{question.label}} is invalid</span>
</div>
</div>
When the form renders to the screen it looks like this:
As you can see, the column widths are gone. I'm certain it has something to do with the div tag holding the FormGroup attribute, but that is required for the component to compile and work. I've tried adding it with a span tag, adding the col-md-6 class to the same tag as FormGroup, but I get the same, incorrect CSS rendering.
Is this another Bootstrap 4 issue where I may need to go down to Bootstrap 3 for this to work? If not, what is going on and how can I get the page to correctly render like the first image and yet still be able to use the app-question component in my code?
I believe that the problem is that Angular renders app-question component as a tag <app-question></app-question> and your div tags inside of it have styles relative to that app-question tag, but not the parent <div class="row">. So if you add a class col-md-6(for example) it will cover 50% of the app-question tag, but not the row one.
So if you want the styles to work, you should add the classes here
<div class="row">
<app-question *ngFor="let question of questions"
[question]="question"
[form]="form"
class="col-md-6">
</app-question>
</div>
As an alternative, you can change your app-question component decorator to make it an attribute.
#Component({
selector: '[app-question]'
})
And then use it to any tag you like
<div class="row">
<div app-question
*ngFor="let question of questions"
[question]="question"
[form]="form"
class="col-md-6">
</app-question>
</div>
Let's say I have HTML like this:
...
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="invalidCheck">
<label class="form-check-label" for="invalidCheck">
Agree to something
</label>
</div>
<div class="invalid-feedback">
I am outside of `form-check`!
</div>
</div>
...
I want to force to show the <div class="invalid-feedback">... without using JavaScript (want to use Bootstrap CSS only). And I know I can use CSS classes like was-validated or is-invalid, but invalid-feedback is outside of form-check. Is there an easy and simple way to show invalid-feedback by adding Bootstrap related CSS classes?
I found one solution:
<div class="invalid-feedback d-block">
Now I am visible!
</div>
But I feel like it's a hacky solution. Please advise!
Use display classes to display it manually for example d-block
use it like so
<div class="valid-feedback d-block">
or
<div class="invalid-feedback d-block">
Find more in documentation
There are better ways.
1)
Look into a was-validated class, that you can set on the form like so
<form action="..." class="was-validated" method="POST" novalidate>
When set on the form it displays validation feedback and also colorcodes the input field.
Just add it conditionally on your form, when validation failed on the server side.
2)
Or you can use some JavaScript to be in control of what is displayed. You can add this class dynamically
$('form').addClass('was-validated');
and you can also dynamically check if the form is valid like so
if ($('form').checkValidity()) {...
I was wondering if anyone has any idea how to do the following.
I want to show all the Brands on the site on a grid on a brands page, similar to how products are shown by default but showing brands (the image & name within a panel) that can be clicked through to take users to that brand page.
I had it working for a second but due to thinking it had failed. I changed the Site settings/code and now I cant remember how to get it back to working.
EDIT:
<div id="Container">
%%Panel.Header%%
<div class="bannerimg">
%%Panel.WrapperBanner%%
</div>
<div class="SideBar"><!-- This is desktop only -->
%%Panel.SideShopByBrand%%
</div>
<div id="Wrapper">
<div class="ContentHead CatHead Center">
%%SNIPPET_CategorySortBox%%
<h1 class="title">%%GLOBAL_PageTitle%%</h1>
%%Panel.PageBreadcrumb%%
</div>
<div class="Content Widest" id="LayoutColumn1">
%%Panel.PageContent%%
TEST
%%Panel.GetInTouch%%
</div>
<div class="clear"></div>
</div>
%%Panel.Footer%%
</div>
The "TEST" string is where I had been trying to add various bits of code to pull in all the brands but most of the time when I add any of that code it breaks the page and nothing loads on a page refresh.
It should be enough to just upload an image for the brands (on /admin/index.php?ToDo=viewBrands page) and it should automatically appear on /brands page.
This is a very strange issue. On the Reveal Form (onclick of "Price and Save My Shopping List"), I thought that for some reason the text box and dropdown were disabled. This is not the case; however, it's only allowing me to click on them on the far right of the control--I had to increase the dropdown to "medium" from "small" to be able to interact with it at all. I have no idea why this is happening and couldn't even think of what to Google. So I've looked at everything related to Foundation Reveal to no avail.
Here is the jsfiddle, but although it works on my site, it does NOT on jsfiddle. If you want to see it in action, I'll send you a link to my site.: http://jsfiddle.net/jenborn/TQjm9/
Here is the modal form since apparently I have to include code if I link to a jsfiddle:
<form id="saveShoppingList" action="" method="POST" class="custom">
<div class="small-12 columns">
<div class="small-6 small-centered columns"><h4>Your Shopping List</h4></div>
<div id="makemebold" class="large-4 columns"><!--label for="name"-->Name it: <!--/label--></div>
<div class="small-8 columns"><input type="text" id="name" name="name" /></div>
<div id="makemebold" class="small-4 columns"><!--label for="style"-->Style: <!--/label--></div>
<div class="small-8 columns"><select id="beer_style" class="medium"><? echo $style_opt ?></select></div>
<div id="makemebold" class="large-4 columns">Keep Private:</div>
<div class="small-3 left columns"><div class="switch tiny round"><input id="private" name="private" type="radio"><label for="private" onclick="Off">On</label><span></span></div></div>
</div>
<div class="row">
<div class="small-6 large-centered columns">
<button type="submit" class="button radius">Go</button>
<button type="reset" class="button radius alert">Reset</button>
</div>
</form>
You have some major issues in your use of Foundation's grid. You have subsequent columns adding up to well over twelve, and columns nested within other columns without an interposing row. If you go through the Foundation Docs' grid section and rewrite your code accordingly, I'm betting your issue will be resolved. Pay special attention to the section titled "Infinitely nest your grid".
I would also suggest basic improvements like using a label element for your form labels, as browsers will know how to use them better. And for semantics, of course.