Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 5d70288

Browse files
committed
doc(cb-a11y): Labelling form controls: content
1 parent e571bfe commit 5d70288

File tree

4 files changed

+88
-25
lines changed

4 files changed

+88
-25
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
/* #docregion */
12
div.edit-box{
23
height: auto;
4+
min-height: 50px;
35
width: 30%;
46
}
7+
/* #enddocregion */

public/docs/_examples/cb-a11y/ts/app/form-controls/a11y-custom-control.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
</label>
66
<div #divTextBox
77
role="textbox"
8-
aria-multiline="false"
8+
aria-multiline="true"
99
[attr.aria-labelledby]="uniqueId"
1010
class="form-control edit-box"
1111
[innerHTML]="outerValue"
1212
(keypress)="onChange($event, divTextBox.innerHTML)"
13+
(blur)="onBlur()"
1314
contenteditable></div>
1415
</div>
1516
<!-- #enddocregion -->

public/docs/_examples/cb-a11y/ts/app/form-controls/a11y-custom-control.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Component, OnInit, Provider, forwardRef,} from "angular2/core";
22
import {A11yHelper} from "../services/a11y-helper.service";
33
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from "angular2/common";
44

5+
// #docregion
56
const noop = () => {
67
};
78

@@ -40,6 +41,10 @@ export class A11yCustomControl implements OnInit, ControlValueAccessor {
4041
}
4142
}
4243

44+
onBlur(){
45+
this._onTouchedCallback();
46+
}
47+
4348
writeValue(value:any) {
4449
if (value != this._innerValue) {
4550
this._innerValue = value;
@@ -60,3 +65,4 @@ export class A11yCustomControl implements OnInit, ControlValueAccessor {
6065
}
6166

6267
}
68+
// #enddocregion

public/docs/ts/latest/cookbook/a11y.jade

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,21 @@ include ../_util-fns
3636

3737
.l-sub-section
3838
:marked
39-
Use this method to label your `form controls` as far as possible. As you will see later the other methods of
40-
labelling relies on generating unique id's for your elements. And as we are often building re-usable components
41-
in Angular&nbsp;2, you will need to insure that every id you create is unique on a page, no matter how often your
42-
component is used! Save yourself the trouble and label implicitly.
39+
`ARIA`, or `Accessible Rich Internet Applications` refers to bringing `a11y` concepts into
40+
internet applications like those we are building with Angular&nbsp;2.
4341

4442
:marked
4543
You can also see what they say about [ARIA](https://www.w3.org/WAI/intro/aria) at the `W3C`. We will be right here
4644
waiting for you when you come back.
45+
46+
.callout.is-important
47+
header ARIA terminology confusion alert!
48+
:marked
49+
In `ARIA` we refer to the `aria-...` attributes as `ARIA States` or `ARIA Properties`. The difference between
50+
the two should become clear as you progress through this cookbook. However, `ARIA Properties` are not
51+
actual `HTML` element properties but decorating attributes refering to properties. When we refer to setting an
52+
`ARIA Property` in the code you will **HAVE** to do
53+
it with an Angular&nbsp;2 attribute binding. This is simply a terminology clash.
4754

4855
.l-main-section
4956
:marked
@@ -107,6 +114,12 @@ include ../_util-fns
107114

108115
[Managing focus](#managin-focus)
109116

117+
.l-sub-section
118+
:marked
119+
In the example application code when we require unique element id's we will be generating `GUID's`to ensure that they are
120+
unique. You can use your own method to do this, as long as every id on a page is unique. More on this later...
121+
122+
:marked
110123
**Feel free to follow along in this [live example](/resources/live-examples/cb-a11y/ts/plnkr.html)**.
111124

112125
.l-main-section
@@ -277,46 +290,86 @@ code-example(language="html" escape="html").
277290
:marked
278291
### Labelling custom form controls
279292

280-
So you have been asked to do something and try as you might you cannot find a native `HTML` element to do the job
281-
**OR** you are want to give that legacy application an `a11y` makeover without having the luxury to rewrite the
293+
So you have been asked to do something and try as you might you cannot construct this with native `HTML` elements
294+
**OR** you are want to give that legacy application an `a11y` makeover without the luxury of rewriting the
282295
entire codebase.
283296

284297
How would you go about making these custom form controls accessible?
285298

286-
Fear not, there is a way!
287-
288-
To avoid writing many lines of code as an example we will create an input field out of a `div`. Rest assured,
289-
not using the native `HTML` elements in practise will cost a lot more code than this to make it fully functional.
290-
Everytime you bend this rule your codebase will grow and become more complex.
291-
292-
Component template:
299+
Fear not, there is a way! We introduce the next addition to our `ARIA` toolkit, and that is `aria-labeledby`.
300+
301+
Why do we need this? Because the native `a11y` function of the `label` element is only recognised when used with
302+
native `HTML` form control elements such as `input` and `textarea`. To label anything else, like a `div` or a
303+
`custom element` we need to create the the link using `aria-labelledby`.
304+
305+
Lets illustrate this by recreating the native `input` element with a component that makes use of `div's`.
306+
307+
.l-sub-section
308+
:marked
309+
Please note that creating an `input` out of `div's` is **NOT** recommended, but only serves as an illustration that
310+
it is possible to make any form controll accessible. And as we are focussing on `a11y`, our component will also not
311+
be production ready but only
312+
implement the basics of functionality to make it function as an `input` i.e. adding the machinery to make it play nice
313+
with `ngModel`. This implementation would need to become
314+
even larger and more complex before it can be used in an enterprise application. We hope that this illustrates
315+
further why the native `HTML` elements should preferably be used.
316+
317+
:marked
318+
Our component:
293319

294-
+makeExample('cb-a11y/ts/app/form-controls/a11y-custom-control.component.html')
320+
+makeTabs('cb-a11y/ts/app/form-controls/a11y-custom-control.component.html,cb-a11y/ts/app/form-controls/a11y-custom-control.component.ts,cb-a11y/ts/app/form-controls/a11y-custom-control.component.css',
321+
null, 'a11y-custom-control.component.html,a11y-custom-control.component.ts, a11y-custom-control.component.css')
295322

296323
:marked
297-
User writes:
324+
This can now be used in our `HTML` as follows:
298325

299326
+makeExample('cb-a11y/ts/app/form-controls/a11y-form-controls.component.html','cb-a11y-form-controls-custom-control-usage')
300327

301328
:marked
302-
Rendered out:
329+
Lets have a look at what is rendered out. *For clarity sake, the style attributes added by Angular&nbsp;2 for the component
330+
style have been omitted.*:
303331

304332
code-example(language="html" escape="html" format="linenums").
305-
<a11y-custom-control>
333+
<a11y-custom-control class="ng-pristine ng-valid ng-untouched">
306334
<div class="form-group">
307-
<label id="9db87459-2e0d-49ea-a8bf-bb7a3a599858">
335+
<label id="60e9545d-8c5c-4c55-f171-e266c50479e9">
308336
Write in this labelled div:
309337
</label>
310-
<div class="form-control" contenteditable="" role="textbox" aria-labelledby="9db87459-2e0d-49ea-a8bf-bb7a3a599858"></div>
338+
<div aria-multiline="true" class="form-control edit-box" contenteditable=""
339+
role="textbox" aria-labelledby="60e9545d-8c5c-4c55-f171-e266c50479e9"></div>
311340
</div>
312341
</a11y-custom-control>
313342

343+
:marked
344+
The first thing that we should note is the `role` attribute. This is also part of `ARIA` and we use these when we need
345+
to tell assistive technologies the functional role a component has. We need to specify this when we are not using the
346+
native `HTML` elements. For those elements the role is already defined. Here, our custom control needs the role of
347+
`textarea`. We will look at `ARIA Roles` in more detail later.
348+
349+
Next we will look at the `aria-labelledby` attribute. As you can see this contains the `id` of the `label` field. This
350+
is how we tell screen readers to use that specific `label` element to label our input control.
351+
314352
.l-sub-section
315353
:marked
316-
In the example application code we are generating `GUID's` for id's to ensure that they are unique. You can use your
317-
own method to do this, as long as every id on a page is unique.
318-
319-
354+
Aside from having to generate unique `id's`, there is one more caveat to using `aria-labelledby`. Even when using this
355+
with an actual `label` element, clicking the label will **NOT** focus the input as it does when used with native
356+
`HTML` form control elements. Therefore this construct will always be slightly inferior to the native approach, as you lose the
357+
accessibility gain the `label click` gives you.
358+
359+
:marked
360+
And finally, while you were not looking we snuck in yet another `ARIA` property called `aria-multiline`. Yes folks,
361+
someone unable to see what is happening also needs to know if our input accepts single or multiple lines of input. Using
362+
`aria-multiline`, we are able to tell the screan reader if it is single or multiline and the screen reader will even
363+
read this information back to the user.
364+
365+
That was certainly a mouthful! Isn't there a middle way where we can use the power of Angular&nbsp;2 but keep the
366+
built-in `a11y` wins the native `HTML` elements give us?
367+
368+
There certainly are. Let's look at one option that uses `Content Projection`.
369+
370+
371+
372+
320373
.l-main-section
321374
<a id="keyboard-shortcuts"></a>
322375
:marked
@@ -336,4 +389,4 @@ code-example(language="html" escape="html" format="linenums").
336389
:marked
337390
## Managing focus
338391

339-
Content coming soon...r
392+
Content coming soon...

0 commit comments

Comments
 (0)