├── README.md
├── aria-current
└── index.html
├── aria-tables
└── index.html
├── autocomplete
├── css
│ ├── autocomplete.css
│ └── glyphicon.css
├── index.html
└── js
│ ├── autocomplete.js
│ └── jquery.js
├── css
└── basic.css
├── disclosure1
├── css
│ └── disclosure.css
├── index.html
└── js
│ └── disclosure.js
├── disclosure2
├── css
│ └── disclosure.css
├── index.html
└── js
│ └── disclosure.js
├── disclosure3
├── css
│ └── disclosure.css
├── index.html
└── js
│ └── disclosure.js
├── index.html
├── link1
├── css
│ └── link.css
├── index.html
└── js
│ └── link.js
├── live1
├── index.html
└── js
│ ├── liveregion.js
│ └── liveregion2.js
├── live2
├── index.html
└── js
│ ├── liveregion.js
│ └── liveregion2.js
├── svg-flowchart
└── index.html
├── svg-line-graph
├── index.html
└── original.html
├── tabpanels1
├── css
│ └── tabpanels.css
├── index.html
└── js
│ └── jQuery.js
├── tabpanels2
├── css
│ └── tabpanels.css
├── index.html
└── js
│ └── jQuery.js
├── toggle1
├── css
│ └── button.css
├── index.html
└── js
│ └── button.js
├── toggle2
├── css
│ └── button.css
├── index.html
└── js
│ └── button.js
├── toggle3
├── css
│ └── button.css
├── index.html
└── js
│ └── button.js
├── toggletip1
├── css
│ └── toggletip.css
├── index.html
└── js
│ ├── toggletip.js
│ └── toggletip.js~
└── toggletip2
├── css
└── toggletip.css
├── index.html
└── js
└── toggletip.js
/README.md:
--------------------------------------------------------------------------------
1 | == Accessible design patterns ==
2 | HTML, CSS, JavaScript and ARIA design patterns
3 | http://ljwatson.github.io/design-patterns/
4 |
--------------------------------------------------------------------------------
/aria-current/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | aria-current design patterns
9 |
10 |
11 |
34 |
35 |
36 |
37 | aria-current
design patterns
38 |
39 | The aria-current
attribute indicates the element that represents the current item within a container or set of related elements. It is an enumerated type attribute that takes one of a number of predefined tokens ("page", "step", "location", "date" or "time"), or which may be set to "true".
40 |
41 | aria-current="date"
42 |
43 | Screen readers should announce "Current date" to indicate that Saturday 16th is the current date in the month.
44 |
45 | Code
46 |
47 | <table>
48 | <caption>July 2016</caption>
49 | <tr>
50 | <th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th><th>Sun</th>
51 | </tr>
52 | <tr>
53 | <td></td><td></td><td></td><td></td><td>1</td><td>2</td><td>3</td>
54 | </tr>
55 | <tr>
56 | <td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td>
57 | </tr>
58 | <tr>
59 | <td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td aria-current="date" >16</td><td>17</td>
60 | </tr>
61 | <tr>
62 | <td>18</td><td>19</td><td>20</td><td>21</td><td>21</td><td>22</td><td>23</td>
63 | </tr>
64 | <tr>
65 | <td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td>
66 | </tr>
67 | <tr>
68 | <td>31</td><td></td><td></td><td></td><td></td><td></td><td></td>
69 | </tr>
70 | </table>
71 |
72 |
73 | Example
74 |
75 |
76 | July 2016
77 |
78 | Mon Tue Wed Thu Fri Sat Sun
79 |
80 |
81 | 1 2 3
82 |
83 |
84 | 4 5 6 7 8 9 10
85 |
86 |
87 | 11 12 13 14 15 16 17
88 |
89 |
90 | 18 19 20 21 21 22 23
91 |
92 |
93 | 24 25 26 27 28 29 30
94 |
95 |
96 | 31
97 |
98 |
99 |
100 |
101 | aria-current="location"
102 |
103 | Screen readers should announce "Current location" to indicate the last link is the current location in the breadcrumb navigation.
104 |
105 | Code
106 |
107 | <nav aria-label="Breadcrumb">
108 | <ul>
109 | <li><a href="/">Home</a></li>
110 | <li><a href="/"> Contact us</a></li>
111 | <li><a href="/" aria-current="location" > Phone numbers</a></li>
112 | </ul>
113 | </nav>
114 |
115 |
116 |
117 | Example
118 |
127 |
128 | aria-current="page"
129 |
130 | Screen readers should announce "Current page" to indicate the first link is the current page in the navigation.
131 |
132 | Code
133 |
134 | <nav>
135 | <ul>
136 | <li><a href="/" aria-current="page" >Home</a></li>
137 | <li><a href="/">About</a></li>
138 | <li><a href="/">Contact</a></li>
139 | </ul>
140 | </nav>
141 |
142 |
143 | Example
144 |
153 |
154 | aria-current="step"
155 |
156 | Screen readers should announce "Current step" to indicate the first link is the current step in the process.
157 |
158 | Code
159 |
160 | <ol>
161 | <li><a href="/" aria-current="step" >Do this</a></li>
162 | <li><a href="/">Do that</a></li>
163 | <li><a href="/">Do the other</a></li>
164 | </ol>
165 |
166 |
167 | Example
168 |
175 |
176 | aria-current="time"
177 |
178 | Screen readers should announce "Current time" to indicate the keynote is happening at the current time in the schedule.
179 |
180 | Code
181 |
182 | <ul>
183 | <li>9am to 10am: Welcome</li>
184 | <li aria-current="time" >10am to 11am: Keynote</li>
185 | <li>11am to 11.30pm: Break</li>
186 | <li>11.30am to 1pm: Workshop</li>
187 | <li>1pm to 2pm: Lunch</li>
188 | <li>2pm to 3pm: Lecture</li>
189 | <li>3pm to 3.30pm: Break</li>
190 | <li>3.30pm to 5pm: Workshop</li>
191 | </ul>
192 |
193 |
194 | Example
195 |
196 |
197 | 9am to 10am: Welcome
198 | 10am to 11am: Keynote
199 | 11am to 11.30pm: Break
200 | 11.30am to 1pm: Workshop
201 | 1pm to 2pm: Lunch
202 | 2pm to 3pm: Lecture
203 | 3pm to 3.30pm: Break
204 | 3.30pm to 5pm: Workshop
205 |
206 |
207 |
208 | aria-current="true"
209 |
210 | Screen readers should announce "Current" to indicate the first link is the current link in the set.
211 |
212 | Code
213 |
214 | <ul>
215 | <li><a href="/" aria-current="true" >Apples</a></li>
216 | <li><a href="/">Bananas</a></li>
217 | <li><a href="/">Cherries</a></li>
218 | </ul>
219 |
220 |
221 | Example
222 |
229 |
230 |
231 | Screen reader support
232 | Unless otherwise stated, tests were carried out on the latest OS, browser, and screen reader version. Last updated on 16 August 2019.
233 |
234 |
235 | Screen reader support for aria-current
236 |
237 | =date"
="location"
="page"
="step"
="time"
="true"
Notes
238 |
239 |
240 |
241 | Jaws/Chrome Yes Yes Yes Yes Yes Yes
242 |
243 |
244 |
245 | Jaws/Edge 44 No No No No No No Issue #48
246 |
247 |
248 |
249 | Jaws/Edge 77 Yes Yes Yes Yes Yes Yes
250 |
251 |
252 |
253 | Jaws/Firefox Yes Yes Yes Yes Yes Yes
254 |
255 |
256 |
257 | Jaws/IE Yes Yes Yes Yes Yes Yes
258 |
259 |
260 |
261 | Narrator/Edge 44 No No No No No No
262 |
263 |
264 |
265 | NVDA/Chrome Yes Yes Yes Yes Yes Yes
266 |
267 |
268 |
269 | NVDA/Edge 44 Yes Yes Yes Yes Yes Yes
270 |
271 |
272 |
273 | NVDA/Edge 77 Yes Yes Yes Yes Yes Yes
274 |
275 |
276 |
277 | NVDA/Firefox Yes Yes Yes Yes Yes Yes
278 |
279 |
280 |
281 | NVDA/IE Yes Yes Yes Yes Yes Yes
282 |
283 |
284 |
285 | TalkBack/Chrome ? ? ? ? ? ?
286 |
287 |
288 |
289 | TalkBack/Firefox No No No No No No
290 |
291 |
292 |
293 | VoiceOver (iOS)/Safari No Yes Yes Yes Yes Yes
294 |
295 |
296 |
297 | VoiceOver (MacOS/Safari Yes Yes Yes Yes Yes Yes
298 |
299 |
300 |
301 | Screen reader demos
302 |
310 |
311 |
312 |
--------------------------------------------------------------------------------
/aria-tables/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | ARIA tables test case
9 |
10 |
11 |
12 |
13 |
14 | ARIA tables test case
15 |
16 | The ARIA table
, columnheader
, rowheader
, row
, and cell
roles, can be used to polyfill native HTML table semantics.
17 |
18 | A screen reader should recognise the structure as a table and indicate how many rows and columns it contains. It should be possible to navigate through the table using the standard commands for each screen reader, and for the appropriate row or column headers to be announced as focus moves between table cells.
19 |
20 |
21 | >
22 | Expenses
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Sales
31 | Expenses
32 | Net
33 |
34 |
35 |
36 | Q1
37 | $ 223
38 | $ 195
39 | $ 28
40 |
41 |
42 |
43 | Q2
44 | $ 183
45 | $ 70
46 | $ 113
47 |
48 |
49 |
50 | Q3
51 | $ 277
52 | $ 88
53 | $ 189
54 |
55 |
56 |
57 | Q4
58 | $ 402
59 | $ 133
60 | $ 269
61 |
62 |
63 |
64 |
65 |
66 | Screen reader support
67 | Unless otherwise stated, tests were carried out on the latest OS, browser, and screen reader version. Last updated on 3rd February 2018.
68 |
69 |
70 | Screen reader support for ARIA tables
71 |
72 |
73 | table columnheader rowheader row/column Notes
74 |
75 |
76 |
77 | Jaws/Chrome Yes Yes Yes Yes
78 |
79 |
80 |
81 | Jaws 2018/Edge No No No No Issue #49
82 |
83 |
84 |
85 | Jaws/Firefox Yes Yes Yes Yes
86 |
87 |
88 |
89 | Jaws/IE Yes Yes Yes Yes
90 |
91 |
92 |
93 | Narrator/Edge Yes Yes Yes Yes Narrator needs to be in scan mode.
94 |
95 |
96 |
97 | Narrator/IE No No No No
98 |
99 |
100 |
101 | NVDA/Edge No No No No
102 |
103 |
104 |
105 | NVDA/Chrome Yes No No No Table is recognised but reported as "0 rows, 0 columns".
106 |
107 |
108 |
109 | NVDA/Firefox Yes No Yes Yes Table, row headers and column headers are recognised, but rows/columns are not.
110 |
111 |
112 |
113 | NVDA/IE No No No No
114 |
115 |
116 |
117 | Talkback/Chrome Part Yes N/A Part Table is recognised, but reported as "4 columns, 0 rows".
118 |
119 | Talkback doesn't support row navigation.
120 |
121 |
122 |
123 | TalkBack/Firefox Yes Yes N/A Part Talkback doesn't support row navigation
124 |
125 |
126 |
127 | Voiceover/Safari (iOS) Yes Yes Yes Yes
128 |
129 |
130 |
131 | VoiceOver/Safari (MacOS) Yes Yes Yes Yes
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/autocomplete/css/autocomplete.css:
--------------------------------------------------------------------------------
1 | .icon-expand {
2 | position: relative;
3 | left: -7px;
4 | font-size: 1.7em;
5 | }
6 |
7 | label {
8 | vertical-align: top;
9 | }
10 | input#ac {
11 | vertical-align: top;
12 | }
13 |
14 | ul[role=listbox] {
15 | color: #000;
16 | background: #fff;
17 | display: none;
18 | position: absolute;
19 | list-style: none;
20 | margin-left: 0;
21 | padding: 0;
22 | outline: 1px solid #999;
23 | padding: 0.5em;
24 | max-height: 12em;
25 | overflow: auto;
26 | }
27 |
28 | ul[role=listbox] li {
29 | margin: 0 -0.5em 0 -0.5em;
30 | padding: 0.5em;
31 | }
32 |
33 | ul[role=listbox] li:hover, ul[role=listbox] li.focused:hover {
34 | color: #333;
35 | background: #ccc;
36 | outline: 1px solid #333;
37 | }
38 |
39 | ul[role=listbox] li.focused {
40 | color: #000;
41 | background: #fc0;
42 | outline: 1px solid #000;
43 | }
44 |
--------------------------------------------------------------------------------
/autocomplete/css/glyphicon.css:
--------------------------------------------------------------------------------
1 |
2 | html,
3 | html .halflings {
4 | -webkit-font-smoothing: antialiased !important;
5 | }
6 | @font-face {
7 | font-family: 'Glyphicons';
8 | src: url('fonts/glyphicons-regular.eot');
9 | src: url('fonts/glyphicons-regular.eot?#iefix') format('embedded-opentype'), url('fonts/glyphicons-regular.woff') format('woff'), url('fonts/glyphicons-regular.ttf') format('truetype'), url('fonts/glyphicons-regular.svg#glyphicons_halflingsregular') format('svg');
10 | font-weight: normal;
11 | font-style: normal;
12 | }
13 | [class^="icon-"], [class*=" icon-"] {
14 | display: inline-block;
15 | font-family: 'Glyphicons';
16 | speak: none;
17 | position: relative;
18 | text-decoration: none;
19 | *display: inline;
20 | *zoom: 1;
21 | }
22 |
23 | .icon-ie-fix [class^="icon-"], .icon-ie-fix [class*=" icon-"] {
24 | font-family: inherit;
25 | }
26 |
27 | .icon-ie-fix [class^="icon-"]:before, .icon-ie-fix [class*=" icon-"]:before {
28 | content: "";
29 | }
30 |
31 | .glyphicons.white:before {
32 | color: #fff;
33 | }
34 | .icon-glass:before {
35 | content: "\e001";
36 | }
37 | .icon-leaf:before {
38 | content: "\e002";
39 | }
40 | .icon-dog:before {
41 | content: "\e003";
42 | }
43 | .icon-user:before {
44 | content: "\e004";
45 | }
46 | .icon-girl:before {
47 | content: "\e005";
48 | }
49 | .icon-car:before {
50 | content: "\e006";
51 | }
52 | .icon-user_add:before {
53 | content: "\e007";
54 | }
55 | .icon-user_remove:before {
56 | content: "\e008";
57 | }
58 | .icon-film:before {
59 | content: "\e009";
60 | }
61 | .icon-magic:before {
62 | content: "\e010";
63 | }
64 | .icon-envelope:before {
65 | content: "\2709";
66 | }
67 | .icon-camera:before {
68 | content: "\e012";
69 | }
70 | .icon-heart:before {
71 | content: "\e013";
72 | }
73 | .icon-beach_umbrella:before {
74 | content: "\e014";
75 | }
76 | .icon-train:before {
77 | content: "\e015";
78 | }
79 | .icon-print:before {
80 | content: "\e016";
81 | }
82 | .icon-bin:before {
83 | content: "\e017";
84 | }
85 | .icon-music:before {
86 | content: "\e018";
87 | }
88 | .icon-note:before {
89 | content: "\e019";
90 | }
91 | .icon-heart_empty:before {
92 | content: "\e020";
93 | }
94 | .icon-home:before {
95 | content: "\e021";
96 | }
97 | .icon-snowflake:before {
98 | content: "\2744";
99 | }
100 | .icon-fire:before {
101 | content: "\e023";
102 | }
103 | .icon-magnet:before {
104 | content: "\e024";
105 | }
106 | .icon-parents:before {
107 | content: "\e025";
108 | }
109 | .icon-binoculars:before {
110 | content: "\e026";
111 | }
112 | .icon-road:before {
113 | content: "\e027";
114 | }
115 | .icon-search:before {
116 | content: "\e028";
117 | }
118 | .icon-cars:before {
119 | content: "\e029";
120 | }
121 | .icon-notes_2:before {
122 | content: "\e030";
123 | }
124 | .icon-pencil:before {
125 | content: "\270F";
126 | }
127 | .icon-bus:before {
128 | content: "\e032";
129 | }
130 | .icon-wifi_alt:before {
131 | content: "\e033";
132 | }
133 | .icon-luggage:before {
134 | content: "\e034";
135 | }
136 | .icon-old_man:before {
137 | content: "\e035";
138 | }
139 | .icon-woman:before {
140 | content: "\e036";
141 | }
142 | .icon-file:before {
143 | content: "\e037";
144 | }
145 | .icon-coins:before {
146 | content: "\e038";
147 | }
148 | .icon-airplane:before {
149 | content: "\2708";
150 | }
151 | .icon-notes:before {
152 | content: "\e040";
153 | }
154 | .icon-stats:before {
155 | content: "\e041";
156 | }
157 | .icon-charts:before {
158 | content: "\e042";
159 | }
160 | .icon-pie_chart:before {
161 | content: "\e043";
162 | }
163 | .icon-group:before {
164 | content: "\e044";
165 | }
166 | .icon-keys:before {
167 | content: "\e045";
168 | }
169 | .icon-calendar:before {
170 | content: "\1F4C5";
171 | }
172 | .icon-router:before {
173 | content: "\e047";
174 | }
175 | .icon-camera_small:before {
176 | content: "\e048";
177 | }
178 | .icon-dislikes:before {
179 | content: "\e049";
180 | }
181 | .icon-star:before {
182 | content: "\e050";
183 | }
184 | .icon-link:before {
185 | content: "\e051";
186 | }
187 | .icon-eye_open:before {
188 | content: "\e052";
189 | }
190 | .icon-eye_close:before {
191 | content: "\e053";
192 | }
193 | .icon-alarm:before {
194 | content: "\e054";
195 | }
196 | .icon-clock:before {
197 | content: "\e055";
198 | }
199 | .icon-stopwatch:before {
200 | content: "\e056";
201 | }
202 | .icon-projector:before {
203 | content: "\e057";
204 | }
205 | .icon-history:before {
206 | content: "\e058";
207 | }
208 | .icon-truck:before {
209 | content: "\e059";
210 | }
211 | .icon-cargo:before {
212 | content: "\e060";
213 | }
214 | .icon-compass:before {
215 | content: "\e061";
216 | }
217 | .icon-keynote:before {
218 | content: "\e062";
219 | }
220 | .icon-paperclip:before {
221 | content: "\e063";
222 | }
223 | .icon-power:before {
224 | content: "\e064";
225 | }
226 | .icon-lightbulb:before {
227 | content: "\e065";
228 | }
229 | .icon-tag:before {
230 | content: "\e066";
231 | }
232 | .icon-tags:before {
233 | content: "\e067";
234 | }
235 | .icon-cleaning:before {
236 | content: "\e068";
237 | }
238 | .icon-ruller:before {
239 | content: "\e069";
240 | }
241 | .icon-gift:before {
242 | content: "\e070";
243 | }
244 | .icon-umbrella:before {
245 | content: "\2602";
246 | }
247 | .icon-book:before {
248 | content: "\e072";
249 | }
250 | .icon-bookmark:before {
251 | content: "\1F516";
252 | }
253 | .icon-wifi:before {
254 | content: "\e074";
255 | }
256 | .icon-cup:before {
257 | content: "\e075";
258 | }
259 | .icon-stroller:before {
260 | content: "\e076";
261 | }
262 | .icon-headphones:before {
263 | content: "\e077";
264 | }
265 | .icon-headset:before {
266 | content: "\e078";
267 | }
268 | .icon-warning_sign:before {
269 | content: "\e079";
270 | }
271 | .icon-signal:before {
272 | content: "\e080";
273 | }
274 | .icon-retweet:before {
275 | content: "\e081";
276 | }
277 | .icon-refresh:before {
278 | content: "\e082";
279 | }
280 | .icon-roundabout:before {
281 | content: "\e083";
282 | }
283 | .icon-random:before {
284 | content: "\e084";
285 | }
286 | .icon-heat:before {
287 | content: "\e085";
288 | }
289 | .icon-repeat:before {
290 | content: "\e086";
291 | }
292 | .icon-display:before {
293 | content: "\e087";
294 | }
295 | .icon-log_book:before {
296 | content: "\e088";
297 | }
298 | .icon-adress_book:before {
299 | content: "\e089";
300 | }
301 | .icon-building:before {
302 | content: "\e090";
303 | }
304 | .icon-eyedropper:before {
305 | content: "\e091";
306 | }
307 | .icon-adjust:before {
308 | content: "\e092";
309 | }
310 | .icon-tint:before {
311 | content: "\e093";
312 | }
313 | .icon-crop:before {
314 | content: "\e094";
315 | }
316 | .icon-vector_path_square:before {
317 | content: "\e095";
318 | }
319 | .icon-vector_path_circle:before {
320 | content: "\e096";
321 | }
322 | .icon-vector_path_polygon:before {
323 | content: "\e097";
324 | }
325 | .icon-vector_path_line:before {
326 | content: "\e098";
327 | }
328 | .icon-vector_path_curve:before {
329 | content: "\e099";
330 | }
331 | .icon-vector_path_all:before {
332 | content: "\e100";
333 | }
334 | .icon-font:before {
335 | content: "\e101";
336 | }
337 | .icon-italic:before {
338 | content: "\e102";
339 | }
340 | .icon-bold:before {
341 | content: "\e103";
342 | }
343 | .icon-text_underline:before {
344 | content: "\e104";
345 | }
346 | .icon-text_strike:before {
347 | content: "\e105";
348 | }
349 | .icon-text_height:before {
350 | content: "\e106";
351 | }
352 | .icon-text_width:before {
353 | content: "\e107";
354 | }
355 | .icon-text_resize:before {
356 | content: "\e108";
357 | }
358 | .icon-left_indent:before {
359 | content: "\e109";
360 | }
361 | .icon-right_indent:before {
362 | content: "\e110";
363 | }
364 | .icon-align_left:before {
365 | content: "\e111";
366 | }
367 | .icon-align_center:before {
368 | content: "\e112";
369 | }
370 | .icon-align_right:before {
371 | content: "\e113";
372 | }
373 | .icon-justify:before {
374 | content: "\e114";
375 | }
376 | .icon-list:before {
377 | content: "\e115";
378 | }
379 | .icon-text_smaller:before {
380 | content: "\e116";
381 | }
382 | .icon-text_bigger:before {
383 | content: "\e117";
384 | }
385 | .icon-embed:before {
386 | content: "\e118";
387 | }
388 | .icon-embed_close:before {
389 | content: "\e119";
390 | }
391 | .icon-table:before {
392 | content: "\e120";
393 | }
394 | .icon-message_full:before {
395 | content: "\e121";
396 | }
397 | .icon-message_empty:before {
398 | content: "\e122";
399 | }
400 | .icon-message_in:before {
401 | content: "\e123";
402 | }
403 | .icon-message_out:before {
404 | content: "\e124";
405 | }
406 | .icon-message_plus:before {
407 | content: "\e125";
408 | }
409 | .icon-message_minus:before {
410 | content: "\e126";
411 | }
412 | .icon-message_ban:before {
413 | content: "\e127";
414 | }
415 | .icon-message_flag:before {
416 | content: "\e128";
417 | }
418 | .icon-message_lock:before {
419 | content: "\e129";
420 | }
421 | .icon-message_new:before {
422 | content: "\e130";
423 | }
424 | .icon-inbox:before {
425 | content: "\e131";
426 | }
427 | .icon-inbox_plus:before {
428 | content: "\e132";
429 | }
430 | .icon-inbox_minus:before {
431 | content: "\e133";
432 | }
433 | .icon-inbox_lock:before {
434 | content: "\e134";
435 | }
436 | .icon-inbox_in:before {
437 | content: "\e135";
438 | }
439 | .icon-inbox_out:before {
440 | content: "\e136";
441 | }
442 | .icon-cogwheel:before {
443 | content: "\e137";
444 | }
445 | .icon-cogwheels:before {
446 | content: "\e138";
447 | }
448 | .icon-picture:before {
449 | content: "\e139";
450 | }
451 | .icon-adjust_alt:before {
452 | content: "\e140";
453 | }
454 | .icon-database_lock:before {
455 | content: "\e141";
456 | }
457 | .icon-database_plus:before {
458 | content: "\e142";
459 | }
460 | .icon-database_minus:before {
461 | content: "\e143";
462 | }
463 | .icon-database_ban:before {
464 | content: "\e144";
465 | }
466 | .icon-folder_open:before {
467 | content: "\e145";
468 | }
469 | .icon-folder_plus:before {
470 | content: "\e146";
471 | }
472 | .icon-folder_minus:before {
473 | content: "\e147";
474 | }
475 | .icon-folder_lock:before {
476 | content: "\e148";
477 | }
478 | .icon-folder_flag:before {
479 | content: "\e149";
480 | }
481 | .icon-folder_new:before {
482 | content: "\e150";
483 | }
484 | .icon-edit:before {
485 | content: "\e151";
486 | }
487 | .icon-new_window:before {
488 | content: "\e152";
489 | }
490 | .icon-check:before {
491 | content: "\e153";
492 | }
493 | .icon-unchecked:before {
494 | content: "\e154";
495 | }
496 | .icon-more_windows:before {
497 | content: "\e155";
498 | }
499 | .icon-show_big_thumbnails:before {
500 | content: "\e156";
501 | }
502 | .icon-show_thumbnails:before {
503 | content: "\e157";
504 | }
505 | .icon-show_thumbnails_with_lines:before {
506 | content: "\e158";
507 | }
508 | .icon-show_lines:before {
509 | content: "\e159";
510 | }
511 | .icon-playlist:before {
512 | content: "\e160";
513 | }
514 | .icon-imac:before {
515 | content: "\e161";
516 | }
517 | .icon-macbook:before {
518 | content: "\e162";
519 | }
520 | .icon-ipad:before {
521 | content: "\e163";
522 | }
523 | .icon-iphone:before {
524 | content: "\e164";
525 | }
526 | .icon-iphone_transfer:before {
527 | content: "\e165";
528 | }
529 | .icon-iphone_exchange:before {
530 | content: "\e166";
531 | }
532 | .icon-ipod:before {
533 | content: "\e167";
534 | }
535 | .icon-ipod_shuffle:before {
536 | content: "\e168";
537 | }
538 | .icon-ear_plugs:before {
539 | content: "\e169";
540 | }
541 | .icon-phone:before {
542 | content: "\e170";
543 | }
544 | .icon-step_backward:before {
545 | content: "\e171";
546 | }
547 | .icon-fast_backward:before {
548 | content: "\e172";
549 | }
550 | .icon-rewind:before {
551 | content: "\e173";
552 | }
553 | .icon-play:before {
554 | content: "\e174";
555 | }
556 | .icon-pause:before {
557 | content: "\e175";
558 | }
559 | .icon-stop:before {
560 | content: "\e176";
561 | }
562 | .icon-forward:before {
563 | content: "\e177";
564 | }
565 | .icon-fast_forward:before {
566 | content: "\e178";
567 | }
568 | .icon-step_forward:before {
569 | content: "\e179";
570 | }
571 | .icon-eject:before {
572 | content: "\e180";
573 | }
574 | .icon-facetime_video:before {
575 | content: "\e181";
576 | }
577 | .icon-download_alt:before {
578 | content: "\e182";
579 | }
580 | .icon-mute:before {
581 | content: "\e183";
582 | }
583 | .icon-volume_down:before {
584 | content: "\e184";
585 | }
586 | .icon-volume_up:before {
587 | content: "\e185";
588 | }
589 | .icon-screenshot:before {
590 | content: "\e186";
591 | }
592 | .icon-move:before {
593 | content: "\e187";
594 | }
595 | .icon-more:before {
596 | content: "\e188";
597 | }
598 | .icon-brightness_reduce:before {
599 | content: "\e189";
600 | }
601 | .icon-brightness_increase:before {
602 | content: "\e190";
603 | }
604 | .icon-circle_plus:before {
605 | content: "\e191";
606 | }
607 | .icon-circle_minus:before {
608 | content: "\e192";
609 | }
610 | .icon-circle_remove:before {
611 | content: "\e193";
612 | }
613 | .icon-circle_ok:before {
614 | content: "\e194";
615 | }
616 | .icon-circle_question_mark:before {
617 | content: "\e195";
618 | }
619 | .icon-circle_info:before {
620 | content: "\e196";
621 | }
622 | .icon-circle_exclamation_mark:before {
623 | content: "\e197";
624 | }
625 | .icon-remove:before {
626 | content: "\e198";
627 | }
628 | .icon-ok:before {
629 | content: "\e199";
630 | }
631 | .icon-ban:before {
632 | content: "\e200";
633 | }
634 | .icon-download:before {
635 | content: "\e201";
636 | }
637 | .icon-upload:before {
638 | content: "\e202";
639 | }
640 | .icon-shopping_cart:before {
641 | content: "\e203";
642 | }
643 | .icon-lock:before {
644 | content: "\1F512";
645 | }
646 | .icon-unlock:before {
647 | content: "\e205";
648 | }
649 | .icon-electricity:before {
650 | content: "\e206";
651 | }
652 | .icon-ok_2:before {
653 | content: "\e207";
654 | }
655 | .icon-remove_2:before {
656 | content: "\e208";
657 | }
658 | .icon-cart_out:before {
659 | content: "\e209";
660 | }
661 | .icon-cart_in:before {
662 | content: "\e210";
663 | }
664 | .icon-left_arrow:before {
665 | content: "\e211";
666 | }
667 | .icon-right_arrow:before {
668 | content: "\e212";
669 | }
670 | .icon-down_arrow:before {
671 | content: "\e213";
672 | }
673 | .icon-up_arrow:before {
674 | content: "\e214";
675 | }
676 | .icon-resize_small:before {
677 | content: "\e215";
678 | }
679 | .icon-resize_full:before {
680 | content: "\e216";
681 | }
682 | .icon-circle_arrow_left:before {
683 | content: "\e217";
684 | }
685 | .icon-circle_arrow_right:before {
686 | content: "\e218";
687 | }
688 | .icon-circle_arrow_top:before {
689 | content: "\e219";
690 | }
691 | .icon-circle_arrow_down:before {
692 | content: "\e220";
693 | }
694 | .icon-play_button:before {
695 | content: "\e221";
696 | }
697 | .icon-unshare:before {
698 | content: "\e222";
699 | }
700 | .icon-share:before {
701 | content: "\e223";
702 | }
703 | .icon-chevron-right:before {
704 | content: "\e224";
705 | }
706 | .icon-chevron-left:before {
707 | content: "\e225";
708 | }
709 | .icon-bluetooth:before {
710 | content: "\e226";
711 | }
712 | .icon-euro:before {
713 | content: "\20AC";
714 | }
715 | .icon-usd:before {
716 | content: "\e228";
717 | }
718 | .icon-gbp:before {
719 | content: "\e229";
720 | }
721 | .icon-retweet_2:before {
722 | content: "\e230";
723 | }
724 | .icon-moon:before {
725 | content: "\e231";
726 | }
727 | .icon-sun:before {
728 | content: "\2609";
729 | }
730 | .icon-cloud:before {
731 | content: "\2601";
732 | }
733 | .icon-direction:before {
734 | content: "\e234";
735 | }
736 | .icon-brush:before {
737 | content: "\e235";
738 | }
739 | .icon-pen:before {
740 | content: "\e236";
741 | }
742 | .icon-zoom_in:before {
743 | content: "\e237";
744 | }
745 | .icon-zoom_out:before {
746 | content: "\e238";
747 | }
748 | .icon-pin:before {
749 | content: "\e239";
750 | }
751 | .icon-albums:before {
752 | content: "\e240";
753 | }
754 | .icon-rotation_lock:before {
755 | content: "\e241";
756 | }
757 | .icon-flash:before {
758 | content: "\e242";
759 | }
760 | .icon-google_maps:before {
761 | content: "\e243";
762 | }
763 | .icon-anchor:before {
764 | content: "\2693";
765 | }
766 | .icon-conversation:before {
767 | content: "\e245";
768 | }
769 | .icon-chat:before {
770 | content: "\e246";
771 | }
772 | .icon-male:before {
773 | content: "\e247";
774 | }
775 | .icon-female:before {
776 | content: "\e248";
777 | }
778 | .icon-asterisk:before {
779 | content: "\002A";
780 | }
781 | .icon-divide:before {
782 | content: "\00F7";
783 | }
784 | .icon-snorkel_diving:before {
785 | content: "\e251";
786 | }
787 | .icon-scuba_diving:before {
788 | content: "\e252";
789 | }
790 | .icon-oxygen_bottle:before {
791 | content: "\e253";
792 | }
793 | .icon-fins:before {
794 | content: "\e254";
795 | }
796 | .icon-fishes:before {
797 | content: "\e255";
798 | }
799 | .icon-boat:before {
800 | content: "\e256";
801 | }
802 | .icon-delete:before {
803 | content: "\e257";
804 | }
805 | .icon-sheriffs_star:before {
806 | content: "\e258";
807 | }
808 | .icon-qrcode:before {
809 | content: "\e259";
810 | }
811 | .icon-barcode:before {
812 | content: "\e260";
813 | }
814 | .icon-pool:before {
815 | content: "\e261";
816 | }
817 | .icon-buoy:before {
818 | content: "\e262";
819 | }
820 | .icon-spade:before {
821 | content: "\e263";
822 | }
823 | .icon-bank:before {
824 | content: "\e264";
825 | }
826 | .icon-vcard:before {
827 | content: "\e265";
828 | }
829 | .icon-electrical_plug:before {
830 | content: "\e266";
831 | }
832 | .icon-flag:before {
833 | content: "\e267";
834 | }
835 | .icon-credit_card:before {
836 | content: "\e268";
837 | }
838 | .icon-keyboard-wireless:before {
839 | content: "\e269";
840 | }
841 | .icon-keyboard-wired:before {
842 | content: "\e270";
843 | }
844 | .icon-shield:before {
845 | content: "\e271";
846 | }
847 | .icon-ring:before {
848 | content: "\02DA";
849 | }
850 | .icon-cake:before {
851 | content: "\e273";
852 | }
853 | .icon-drink:before {
854 | content: "\e274";
855 | }
856 | .icon-beer:before {
857 | content: "\e275";
858 | }
859 | .icon-fast_food:before {
860 | content: "\e276";
861 | }
862 | .icon-cutlery:before {
863 | content: "\e277";
864 | }
865 | .icon-pizza:before {
866 | content: "\e278";
867 | }
868 | .icon-birthday_cake:before {
869 | content: "\e279";
870 | }
871 | .icon-tablet:before {
872 | content: "\e280";
873 | }
874 | .icon-settings:before {
875 | content: "\e281";
876 | }
877 | .icon-bullets:before {
878 | content: "\e282";
879 | }
880 | .icon-cardio:before {
881 | content: "\e283";
882 | }
883 | .icon-t-shirt:before {
884 | content: "\e284";
885 | }
886 | .icon-pants:before {
887 | content: "\e285";
888 | }
889 | .icon-sweater:before {
890 | content: "\e286";
891 | }
892 | .icon-fabric:before {
893 | content: "\e287";
894 | }
895 | .icon-leather:before {
896 | content: "\e288";
897 | }
898 | .icon-scissors:before {
899 | content: "\e289";
900 | }
901 | .icon-bomb:before {
902 | content: "\e290";
903 | }
904 | .icon-skull:before {
905 | content: "\e291";
906 | }
907 | .icon-celebration:before {
908 | content: "\e292";
909 | }
910 | .icon-tea_kettle:before {
911 | content: "\e293";
912 | }
913 | .icon-french_press:before {
914 | content: "\e294";
915 | }
916 | .icon-coffe_cup:before {
917 | content: "\e295";
918 | }
919 | .icon-pot:before {
920 | content: "\e296";
921 | }
922 | .icon-grater:before {
923 | content: "\e297";
924 | }
925 | .icon-kettle:before {
926 | content: "\e298";
927 | }
928 | .icon-hospital:before {
929 | content: "\e299";
930 | }
931 | .icon-hospital_h:before {
932 | content: "\e300";
933 | }
934 | .icon-microphone:before {
935 | content: "\e301";
936 | }
937 | .icon-webcam:before {
938 | content: "\e302";
939 | }
940 | .icon-temple_christianity_church:before {
941 | content: "\e303";
942 | }
943 | .icon-temple_islam:before {
944 | content: "\e304";
945 | }
946 | .icon-temple_hindu:before {
947 | content: "\e305";
948 | }
949 | .icon-temple_buddhist:before {
950 | content: "\e306";
951 | }
952 | .icon-bicycle:before {
953 | content: "\e307";
954 | }
955 | .icon-life_preserver:before {
956 | content: "\e308";
957 | }
958 | .icon-share_alt:before {
959 | content: "\e309";
960 | }
961 | .icon-comments:before {
962 | content: "\e310";
963 | }
964 | .icon-flower:before {
965 | content: "\2698";
966 | }
967 | .icon-baseball:before {
968 | content: "\e312";
969 | }
970 | .icon-rugby:before {
971 | content: "\e313";
972 | }
973 | .icon-ax:before {
974 | content: "\e314";
975 | }
976 | .icon-table_tennis:before {
977 | content: "\e315";
978 | }
979 | .icon-bowling:before {
980 | content: "\e316";
981 | }
982 | .icon-tree_conifer:before {
983 | content: "\e317";
984 | }
985 | .icon-tree_deciduous:before {
986 | content: "\e318";
987 | }
988 | .icon-more_items:before {
989 | content: "\e319";
990 | }
991 | .icon-sort:before {
992 | content: "\e320";
993 | }
994 | .icon-filter:before {
995 | content: "\e321";
996 | }
997 | .icon-gamepad:before {
998 | content: "\e322";
999 | }
1000 | .icon-playing_dices:before {
1001 | content: "\e323";
1002 | }
1003 | .icon-calculator:before {
1004 | content: "\e324";
1005 | }
1006 | .icon-tie:before {
1007 | content: "\e325";
1008 | }
1009 | .icon-wallet:before {
1010 | content: "\e326";
1011 | }
1012 | .icon-piano:before {
1013 | content: "\e327";
1014 | }
1015 | .icon-sampler:before {
1016 | content: "\e328";
1017 | }
1018 | .icon-podium:before {
1019 | content: "\e329";
1020 | }
1021 | .icon-soccer_ball:before {
1022 | content: "\e330";
1023 | }
1024 | .icon-blog:before {
1025 | content: "\e331";
1026 | }
1027 | .icon-dashboard:before {
1028 | content: "\e332";
1029 | }
1030 | .icon-certificate:before {
1031 | content: "\e333";
1032 | }
1033 | .icon-bell:before {
1034 | content: "\e334";
1035 | }
1036 | .icon-candle:before {
1037 | content: "\e335";
1038 | }
1039 | .icon-pushpin:before {
1040 | content: "\e336";
1041 | }
1042 | .icon-iphone_shake:before {
1043 | content: "\e337";
1044 | }
1045 | .icon-pin_flag:before {
1046 | content: "\e338";
1047 | }
1048 | .icon-turtle:before {
1049 | content: "\e339";
1050 | }
1051 | .icon-rabbit:before {
1052 | content: "\e340";
1053 | }
1054 | .icon-globe:before {
1055 | content: "\e341";
1056 | }
1057 | .icon-briefcase:before {
1058 | content: "\1F4BC";
1059 | }
1060 | .icon-hdd:before {
1061 | content: "\e343";
1062 | }
1063 | .icon-thumbs_up:before {
1064 | content: "\e344";
1065 | }
1066 | .icon-thumbs_down:before {
1067 | content: "\e345";
1068 | }
1069 | .icon-hand_right:before {
1070 | content: "\e346";
1071 | }
1072 | .icon-hand_left:before {
1073 | content: "\e347";
1074 | }
1075 | .icon-hand_up:before {
1076 | content: "\e348";
1077 | }
1078 | .icon-hand_down:before {
1079 | content: "\e349";
1080 | }
1081 | .icon-fullscreen:before {
1082 | content: "\e350";
1083 | }
1084 | .icon-shopping_bag:before {
1085 | content: "\e351";
1086 | }
1087 | .icon-book_open:before {
1088 | content: "\e352";
1089 | }
1090 | .icon-nameplate:before {
1091 | content: "\e353";
1092 | }
1093 | .icon-nameplate_alt:before {
1094 | content: "\e354";
1095 | }
1096 | .icon-vases:before {
1097 | content: "\e355";
1098 | }
1099 | .icon-bullhorn:before {
1100 | content: "\e356";
1101 | }
1102 | .icon-dumbbell:before {
1103 | content: "\e357";
1104 | }
1105 | .icon-suitcase:before {
1106 | content: "\e358";
1107 | }
1108 | .icon-file_import:before {
1109 | content: "\e359";
1110 | }
1111 | .icon-file_export:before {
1112 | content: "\e360";
1113 | }
1114 | .icon-bug:before {
1115 | content: "\e361";
1116 | }
1117 | .icon-crown:before {
1118 | content: "\e362";
1119 | }
1120 | .icon-smoking:before {
1121 | content: "\e363";
1122 | }
1123 | .icon-cloud-upload:before {
1124 | content: "\e364";
1125 | }
1126 | .icon-cloud-download:before {
1127 | content: "\e365";
1128 | }
1129 | .icon-restart:before {
1130 | content: "\e366";
1131 | }
1132 | .icon-security_camera:before {
1133 | content: "\e367";
1134 | }
1135 | .icon-expand:before {
1136 | content: "\e368";
1137 | }
1138 | .icon-collapse:before {
1139 | content: "\e369";
1140 | }
1141 | .icon-collapse_top:before {
1142 | content: "\e370";
1143 | }
1144 | .icon-globe_af:before {
1145 | content: "\e371";
1146 | }
1147 | .icon-global:before {
1148 | content: "\e372";
1149 | }
1150 | .icon-spray:before {
1151 | content: "\e373";
1152 | }
1153 | .icon-nails:before {
1154 | content: "\e374";
1155 | }
1156 | .icon-claw_hammer:before {
1157 | content: "\e375";
1158 | }
1159 | .icon-classic_hammer:before {
1160 | content: "\e376";
1161 | }
1162 | .icon-hand_saw:before {
1163 | content: "\e377";
1164 | }
1165 | .icon-riflescope:before {
1166 | content: "\e378";
1167 | }
1168 | .icon-electrical_socket_eu:before {
1169 | content: "\e379";
1170 | }
1171 | .icon-electrical_socket_us:before {
1172 | content: "\e380";
1173 | }
1174 | .icon-pinterest:before {
1175 | content: "\e381";
1176 | }
1177 | .icon-dropbox:before {
1178 | content: "\e382";
1179 | }
1180 | .icon-google_plus:before {
1181 | content: "\e383";
1182 | }
1183 | .icon-jolicloud:before {
1184 | content: "\e384";
1185 | }
1186 | .icon-yahoo:before {
1187 | content: "\e385";
1188 | }
1189 | .icon-blogger:before {
1190 | content: "\e386";
1191 | }
1192 | .icon-picasa:before {
1193 | content: "\e387";
1194 | }
1195 | .icon-amazon:before {
1196 | content: "\e388";
1197 | }
1198 | .icon-tumblr:before {
1199 | content: "\e389";
1200 | }
1201 | .icon-wordpress:before {
1202 | content: "\e390";
1203 | }
1204 | .icon-instapaper:before {
1205 | content: "\e391";
1206 | }
1207 | .icon-evernote:before {
1208 | content: "\e392";
1209 | }
1210 | .icon-xing:before {
1211 | content: "\e393";
1212 | }
1213 | .icon-zootool:before {
1214 | content: "\e394";
1215 | }
1216 | .icon-dribbble:before {
1217 | content: "\e395";
1218 | }
1219 | .icon-deviantart:before {
1220 | content: "\e396";
1221 | }
1222 | .icon-read_it_later:before {
1223 | content: "\e397";
1224 | }
1225 | .icon-linked_in:before {
1226 | content: "\e398";
1227 | }
1228 | .icon-forrst:before {
1229 | content: "\e399";
1230 | }
1231 | .icon-pinboard:before {
1232 | content: "\e400";
1233 | }
1234 | .icon-behance:before {
1235 | content: "\e401";
1236 | }
1237 | .icon-github:before {
1238 | content: "\e402";
1239 | }
1240 | .icon-youtube:before {
1241 | content: "\e403";
1242 | }
1243 | .icon-skitch:before {
1244 | content: "\e404";
1245 | }
1246 | .icon-foursquare:before {
1247 | content: "\e405";
1248 | }
1249 | .icon-quora:before {
1250 | content: "\e406";
1251 | }
1252 | .icon-badoo:before {
1253 | content: "\e407";
1254 | }
1255 | .icon-spotify:before {
1256 | content: "\e408";
1257 | }
1258 | .icon-stumbleupon:before {
1259 | content: "\e409";
1260 | }
1261 | .icon-readability:before {
1262 | content: "\e410";
1263 | }
1264 | .icon-facebook:before {
1265 | content: "\e411";
1266 | }
1267 | .icon-twitter:before {
1268 | content: "\e412";
1269 | }
1270 | .icon-instagram:before {
1271 | content: "\e413";
1272 | }
1273 | .icon-posterous_spaces:before {
1274 | content: "\e414";
1275 | }
1276 | .icon-vimeo:before {
1277 | content: "\e415";
1278 | }
1279 | .icon-flickr:before {
1280 | content: "\e416";
1281 | }
1282 | .icon-last_fm:before {
1283 | content: "\e417";
1284 | }
1285 | .icon-rss:before {
1286 | content: "\e418";
1287 | }
1288 | .icon-skype:before {
1289 | content: "\e419";
1290 | }
1291 | .icon-e-mail:before {
1292 | content: "\e420";
1293 | }
1294 | .icon-phone_alt:before {
1295 | content: "\e442";
1296 | }
--------------------------------------------------------------------------------
/autocomplete/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Autocomplete design pattern
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Autocomplete design pattern
20 |
21 | Type into the edit box and a list of autocomplete suggestions appears.
22 |
23 |
24 |
Language:
25 |
26 |
ActionScript AppleScript Asp BASIC C C++ Clojure COBOL ColdFusion Erlang Fortran Groovy Haskell Java JavaScript Lisp Perl PHP Python Ruby Scala Scheme
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/autocomplete/js/autocomplete.js:
--------------------------------------------------------------------------------
1 | function selectItem(objAutocomplete, objCurrent, objNext) {
2 | if (objNext) {
3 | $(objCurrent).removeClass('focused');
4 | $(objNext).addClass('focused');
5 | $(objAutocomplete).attr('aria-activedescendant', $(objNext).attr('id'));
6 | $(objAutocomplete).val($(objNext).text());
7 | $(objNext).focus();
8 | }
9 | }
10 |
11 | function displayMenu(objAutocomplete, bEmpty) {
12 | var strSearch = $(objAutocomplete).attr('data-typed').replace(/^\s*|\s*$/g, '').toLowerCase();
13 | var iVisible = 0;
14 |
15 | if (bEmpty || strSearch.length > 0) {
16 | $('#suggestions').find('li').each(function() {
17 | if ($(this).text().toLowerCase().indexOf(strSearch) < 0) {
18 | $(this).hide();
19 | }
20 | else {
21 | $(this).show();
22 | iVisible++;
23 | }
24 | });
25 | }
26 |
27 | return iVisible;
28 | }
29 |
30 | function showMenu(objAutocomplete, objEvent) {
31 | var iVisible;
32 |
33 | $(objAutocomplete).attr('data-typed', '');
34 | iVisible = displayMenu(objAutocomplete, true);
35 |
36 | if ($(objEvent.target).attr('class') === 'icon-expand') {
37 | if (iVisible && $('#suggestions').css('display') === 'none') {
38 | $('#suggestions').show();
39 | $(objAutocomplete).attr('aria-expanded', 'true');
40 | }
41 | else {
42 | $('#suggestions').hide();
43 | $(objAutocomplete).attr('aria-expanded', 'false');
44 | }
45 | }
46 | else {
47 | $('#suggestions').hide();
48 | $(objAutocomplete).attr('aria-expanded', 'false');
49 | }
50 | }
51 |
52 | function select(objItem, objEvent) {
53 | var objTarget = objEvent.target;
54 |
55 | $('#ac').val($(objTarget).text());
56 | $('#ac').attr('aria-expanded', 'false').attr('data-selected', $('#ac').val());
57 | $('#suggestions').find('li').removeClass('focused');
58 | $(objTarget).addClass('focused');
59 | $('#ac').attr('aria-activedescendant', $(objTarget).attr('id'));
60 | $('#suggestions').hide();
61 | }
62 |
63 | function suggest(objAutocomplete, objEvent) {
64 | var objCurrent, objNext, iVisible, iIndex, bDisplay = true;
65 | if ($(objAutocomplete).attr('aria-activedescendant')) {
66 | objCurrent = $('#suggestions').find('li#' + $(objAutocomplete).attr('aria-activedescendant'));
67 | }
68 |
69 | switch (objEvent.keyCode) {
70 | case 9: // TAB
71 | if ($(objAutocomplete).attr('data-selected').length > 0) {
72 | $(objAutocomplete).val($(objAutocomplete).attr('data-selected'));
73 | }
74 | else {
75 | $(objAutocomplete).val($(objAutocomplete).attr('data-typed'));
76 | }
77 | $('#suggestions').hide();
78 | $(objAutocomplete).select();
79 | bDisplay = false;
80 | break;
81 | case 16: // SHIFT
82 | return false;
83 | case 13: // ENTER
84 | case 32: // SPACE
85 | $(objAutocomplete).attr('data-selected', $(objAutocomplete).val());
86 | $('#suggestions').hide();
87 | bDisplay = false;
88 | if ($(objEvent.target).prop('tagName') === 'LI') {
89 | $(objAutocomplete).focus();
90 | }
91 | objEvent.preventDefault();
92 | break;
93 | case 27: // ESCAPE
94 | if ($(objAutocomplete).attr('data-selected').length > 0) {
95 | $(objAutocomplete).val($(objAutocomplete).attr('data-selected'));
96 | }
97 | else {
98 | $(objAutocomplete).val($(objAutocomplete).attr('data-typed'));
99 | }
100 | $(objAutocomplete).attr('aria-activedescendant', '');
101 | $('#suggestions').find('li').removeClass('focused');
102 | $('#suggestions').hide();
103 | bDisplay = false;
104 | if ($(objEvent.target).prop('tagName') === 'LI') {
105 | $(objAutocomplete).focus();
106 | }
107 | objEvent.preventDefault();
108 | break;
109 | case 38: //UP
110 | if ($('#suggestions').css('display') === 'block') {
111 | if ($(objAutocomplete).attr('data-typed').length > 0) {
112 | iVisible = displayMenu(objAutocomplete, false);
113 | }
114 | else {
115 | iVisible = displayMenu(objAutocomplete, true);
116 | }
117 | if (iVisible > 0 ) {
118 | if (!$(objAutocomplete).attr('aria-activedescendant')) {
119 | objNext = $('#suggestions').find('li:visible:last');
120 | }
121 | else {
122 | iIndex = parseInt($('#suggestions').find('li:visible').index(objCurrent), 10) - 1;
123 | if (iIndex >= 0) {
124 | objNext = $('#suggestions').find('li:visible').get(iIndex);
125 | }
126 | else {
127 | objNext = $('#suggestions').find('li:visible:last');
128 | }
129 | }
130 | selectItem(objAutocomplete, objCurrent, objNext);
131 | }
132 | }
133 |
134 | objEvent.preventDefault();
135 | break;
136 | case 40: //DOWN
137 | if ($(objAutocomplete).attr('data-typed').length > 0) {
138 | iVisible = displayMenu(objAutocomplete, false);
139 | }
140 | else {
141 | iVisible = displayMenu(objAutocomplete, true);
142 | }
143 | if (iVisible > 0 ) {
144 | if (!$(objAutocomplete).attr('aria-activedescendant')) {
145 | objNext = $('#suggestions').find('li:visible')[0];
146 | }
147 | else {
148 | iIndex = parseInt($('#suggestions').find('li:visible').index(objCurrent), 10) + 1;
149 | if (iIndex < $('#suggestions').find('li:visible').length) {
150 | objNext = $('#suggestions').find('li:visible').get(iIndex);
151 | }
152 | else {
153 | objNext = $('#suggestions').find('li:visible')[0];
154 | }
155 | }
156 | selectItem(objAutocomplete, objCurrent, objNext);
157 | }
158 |
159 | objEvent.preventDefault();
160 | break;
161 | default:
162 | if ($(objEvent.target).prop('tagName') === 'LI') {
163 | $(objAutocomplete).focus();
164 | }
165 | $(objAutocomplete).attr('data-typed', $(objAutocomplete).val());
166 | iVisible = displayMenu(objAutocomplete, false);
167 | if (iVisible > 0) {
168 | $('#feedback').html(iVisible + ' results are available');
169 | }
170 | else {
171 | $('#feedback').html('No search results');
172 | }
173 | setTimeout(function(){$('#feedback').html('');}, 1000);
174 | }
175 |
176 | if (bDisplay && iVisible) {
177 | $('#suggestions').show();
178 | $(objAutocomplete).attr('aria-expanded', 'true');
179 | }
180 | else {
181 | $('#suggestions').hide();
182 | $(objAutocomplete).attr('aria-expanded', 'false');
183 | }
184 |
185 | return false;
186 | }
187 |
188 | function loadMenu(arLanguages) {
189 | var objList = $('');
190 | var iPos = $('#ac').offset();
191 | var iWidth = $('#ac').width();
192 |
193 | $.each(arLanguages, function(iKey, strValue) {
194 | objList.append('' + strValue + ' ');
195 | });
196 |
197 | $(objList).insertAfter($('#ac').next());
198 | $(objList).click(function(event){select(this, event);});
199 | $(objList).css({'left': iPos.left + 2, 'top': iPos.top + 6, 'width': iWidth});
200 | $(objList).keydown(function(event){suggest($('#ac'), event);});
201 | }
202 |
203 | $(document).ready(function() {
204 | var objAutocomplete = $('#ac');
205 | var arLanguages = [
206 | 'ActionScript',
207 | 'AppleScript',
208 | 'Asp',
209 | 'BASIC',
210 | 'C',
211 | 'C++',
212 | 'Clojure',
213 | 'COBOL',
214 | 'ColdFusion',
215 | 'Erlang',
216 | 'Fortran',
217 | 'Groovy',
218 | 'Haskell',
219 | 'Java',
220 | 'JavaScript',
221 | 'Lisp',
222 | 'Perl',
223 | 'PHP',
224 | 'Python',
225 | 'Ruby',
226 | 'Scala',
227 | 'Scheme'];
228 |
229 | objAutocomplete.attr('role', 'combobox')
230 | .attr('aria-autocomplete', 'list')
231 | .attr('aria-expanded', 'false')
232 | .attr('aria-owns', 'suggestions')
233 | .attr('aria-labelledby', $(objAutocomplete).prev().attr('id'))
234 | .attr('data-typed', '')
235 | .attr('data-selected', '')
236 | .parent().append(' ');
237 | $('body').click(function(event){showMenu($('#ac'), event);});
238 | $('body').append('
');
239 | objAutocomplete.keyup(function(event){suggest(this, event);});
240 | loadMenu(arLanguages);
241 | });
--------------------------------------------------------------------------------
/css/basic.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | font: normal 95% Helvetica, Verdana, Arial, sans-serif;
3 | color: #000;
4 | padding: 0;
5 | margin: 0;
6 | }
7 |
8 | body {
9 | padding: 0.5em 0.7em;
10 | margin: 0 4em 0 1em;
11 | max-width: 55em;
12 | background: #fff;
13 | }
14 |
15 | h1, h2, h3 {
16 | margin-bottom: 0;
17 | background: transparent;
18 | }
19 |
20 | h1 {
21 | padding: 0.2em;
22 | }
23 |
24 | a {
25 | color: #009;
26 | background: transparent;
27 | }
28 |
29 | a:visited {
30 | color:#360;
31 | background:transparent;
32 | }
33 |
34 | a:hover, a:focus, a:active {
35 | color:#000;
36 | background-color: #fc0;
37 | }
38 |
39 | img {
40 | border: none;
41 | }
42 |
43 | code {
44 | font: bold "Courier new", Courier, Monospace;
45 | }
46 |
47 | mark {
48 | color: #fff;
49 | background-color: #820bbb;
50 | }
51 |
52 | .example {
53 | margin-top: 1em;
54 | margin-bottom: 2em;
55 | }
56 |
--------------------------------------------------------------------------------
/disclosure1/css/disclosure.css:
--------------------------------------------------------------------------------
1 | /* button */
2 |
3 | button {
4 | display: block;
5 | width: 8em;
6 | font-size: 1.1em;
7 | font-weight: bold;
8 | text-align: left;
9 | padding: 0.5em 1em;
10 | color: #ccc;
11 | background-color: #555;
12 | border: 0 none;
13 | border-radius: 3px;
14 | text-shadow: 0 -1px 0 #000;
15 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.6);
16 | }
17 |
18 | button:hover, button:focus {
19 | background-color: #820bbb;
20 | color: #fff;
21 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
22 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
23 | cursor: pointer;
24 | }
25 |
26 | button[aria-expanded="false"] #icon:after {
27 | font-size: 0.75em;
28 | padding-left: 0.5em;
29 | content: "\25BC";
30 | }
31 |
32 | button[aria-expanded="true"] #icon:after {
33 | font-size: 0.75em;
34 | padding-left: 0.5em;
35 | content: "\25B2";
36 | }
37 |
38 | /* content panel */
39 |
40 | div[hidden="true"] {
41 | display: none;
42 | }
43 |
44 | div[id="content"] {
45 | border: 1px #000 solid;
46 | padding: 1em;
47 | background: #555;
48 | color: #FFF;
49 | }
50 |
--------------------------------------------------------------------------------
/disclosure1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Disclosure button design pattern: <button> element
9 |
10 |
11 |
12 |
13 |
14 |
15 | Disclosure button design pattern: <button>
element
16 |
17 | This disclosure button is created using the <button>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | Example
20 |
21 |
Tequila
22 |
23 |
Makes me happy!
24 |
25 |
26 |
27 | Notes
28 |
29 | Using the <button>
element means the browser handles keyboard interaction automatically. The button can be focused on with the keyboard, and it can be activated using either the space or enter keys.
30 |
31 | The aria-expanded
attribute is used to indicate the state of the disclosure widget. It is applied to the <button>
so that assistive technologies can determine the state of the widget whether it is expanded or collapsed. The aria-expanded
attribute is set to false (collapsed) initially, then scripted to toggle between true and false whenever the button is activated.
32 |
33 | The aria-controls
attribute is used to create a relationship between the <button>
and the <div>
that contains the content. It takes the idref of the <div>
as its value. This enables assistive technologies to provide specific commands for moving focus from the <button>
to the <div>
.
34 |
35 | The hidden
attribute indicates the state of the <div>
containing the content. It is used to hide the content both visually and from assistive technologies. The hidden
attribute is added initially, then scripted to be added or removed whenever the button is activated.
36 |
37 | The visible style of the <button>
when pressed is hooked to the aria-expanded
attribute. Similarly the visibility of the <div>
is hooked to the hidden
attribute.
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/disclosure1/js/disclosure.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var button = document.getElementById('button');
5 | var icon = document.getElementById('icon');
6 | var content = document.getElementById('content');
7 |
8 | button.setAttribute('aria-expanded', 'false');
9 | icon.setAttribute('aria-hidden', 'true');
10 | content.setAttribute('hidden', 'true');
11 |
12 | function disclose(event) {
13 | if (content.hasAttribute('hidden')) {
14 | button.setAttribute('aria-expanded', 'true');
15 | button.setAttribute('aria-controls', 'content');
16 | content.removeAttribute('hidden');
17 | }
18 | else {
19 | button.setAttribute('aria-expanded', 'false');
20 | content.setAttribute('hidden', 'true');
21 | button.removeAttribute('aria-controls');
22 | }
23 | }
24 |
25 | button.addEventListener('click', disclose, false);
26 |
27 | })();
28 |
--------------------------------------------------------------------------------
/disclosure2/css/disclosure.css:
--------------------------------------------------------------------------------
1 | /* button */
2 |
3 | [role="button"],[role="button"]:visited {
4 | display: block;
5 | height: 15px;
6 | width: 80px;
7 | font-size: 1.1em;
8 | font-weight: bold;
9 | padding: 10px 15px;
10 | color: #ccc;
11 | background-color: #555;
12 | border: 0 none;
13 | border-radius: 3px;
14 | text-decoration: none;
15 | text-shadow: 0 -1px 0 #000;
16 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
17 | }
18 |
19 | [role="button"]:hover, [role="button"]:focus {
20 | background-color: #820bbb;
21 | color: #fff;
22 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
23 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
24 | cursor: pointer;
25 | }
26 |
27 | [role="button"][aria-expanded="false"] #icon:after {
28 | font-size: 0.75em;
29 | padding-left: 0.5em;
30 | content: "\25BC";
31 | }
32 |
33 | [role="button"][aria-expanded="true"] #icon:after {
34 | font-size: 0.75em;
35 | padding-left: 0.5em;content: "\25B2";
36 | }
37 |
38 | /* content panel */
39 |
40 | div[id="content"] {
41 | // display: block;
42 | border: 1px #000 solid;
43 | padding: 1em;
44 | background: #555;
45 | color: #FFF;
46 | }
47 |
--------------------------------------------------------------------------------
/disclosure2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Disclosure button design pattern: <a> element
9 |
10 |
11 |
12 |
13 |
14 |
15 | Disclosure button design pattern: <a>
element
16 |
17 | This disclosure button is created using the <a>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | It is better to use the <button>
element to create a disclosure button because the browser will automatically provide keyboard support and most semantic information.
20 |
21 | Example
22 |
23 |
24 |
Tequila
25 |
26 |
Makes me happy!
27 |
28 |
29 |
30 | Notes
31 |
32 | Uses the HTML tabindex
attribute with a value of 0. This places the <span>
into the tab order based on its location in the source code. The visual appearance of the button changes when focus moves to it.
33 |
34 | Uses the ARIA role
attribute with a value of button . This instructs the browser to expose the <span>
element as a button through its accessibility API. This information is used by assistive technologies to inform users what they're dealing with.
35 |
36 | Keyboard interaction for the button control is handled through scripting. Both enter and space key events are captured, and used to trigger the button's expected behaviour.
37 |
38 | The aria-expanded
attribute is used to indicate the state of the disclosure widget. It is applied to the <span>
so that assistive technologies can determine the state of the widget whether it is expanded or collapsed. The aria-expanded
attribute is set to false (collapsed) initially, then scripted to toggle between true and false whenever the button is activated.
39 |
40 | The aria-controls
attribute is used to create a relationship between the <span>
and the <div>
that contains the content. It takes the idref of the <div>
as its value. This enables assistive technologies to provide specific commands for moving focus from the <span>
to the <div>
.
41 |
42 | The hidden
attribute indicates the state of the <div>
containing the content. It is used to hide the content both visually and from assistive technologies. The hidden
attribute is added initially, then scripted to be added or removed whenever the button is activated.
43 |
44 | The visible style of the <button>
when pressed is hooked to the aria-expanded
attribute. Similarly the visibility of the <div>
is hooked to the aria-hidden
attribute using CSS selectors . This has no direct impact on accessibility, but it creates a cleaner separation between structure and design.
45 |
46 | Note: There is an issue with Firefox, where content with aria-hidden
is exposed to assistive technologies when inside a <button>
or an element with role="button"
applied. Refer to bug 1147359 for more information.
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/disclosure2/js/disclosure.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var button = document.getElementById('button');
5 | var icon = document.getElementById('icon');
6 | var content = document.getElementById('content');
7 |
8 | button.setAttribute('role', 'button');
9 | button.setAttribute('aria-expanded', 'false');
10 | icon.setAttribute('aria-hidden', 'true');
11 | content.setAttribute('hidden', 'true');
12 |
13 | function disclose(event) {
14 | if (content.hasAttribute('hidden')) {
15 | button.setAttribute('aria-expanded', 'true');
16 | button.setAttribute('aria-controls', 'content');
17 | content.removeAttribute('hidden');
18 | }
19 | else {
20 | button.setAttribute('aria-expanded', 'false');
21 | content.setAttribute('hidden', 'true');
22 | button.removeAttribute('aria-controls');
23 | }
24 | }
25 |
26 | button.addEventListener('click', disclose, false);
27 |
28 | button.addEventListener('keydown', function(event) {
29 | if (event.keyCode ==32) {
30 | disclose();
31 | }
32 | });
33 |
34 | })();
35 |
--------------------------------------------------------------------------------
/disclosure3/css/disclosure.css:
--------------------------------------------------------------------------------
1 | /* button */
2 |
3 | [role="button"] {
4 | display: block;
5 | height: 15px;
6 | width: 80px;
7 | font-size: 1.1em;
8 | font-weight: bold;
9 | padding: 10px 15px;
10 | color: #ccc;
11 | background-color: #555;
12 | border: 0 none;
13 | border-radius: 3px;
14 | text-shadow: 0 -1px 0 #000;
15 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
16 | }
17 |
18 | [role="button"]:hover, [role="button"]:focus {
19 | background-color: #820bbb;
20 | color: #fff;
21 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
22 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
23 | cursor: pointer;
24 | }
25 |
26 | [role="button"][aria-expanded="false"] #icon:after {
27 | font-size: 0.75em;
28 | padding-left: 0.5em;
29 | content: "\25BC";
30 | }
31 |
32 | [role="button"][aria-expanded="true"] #icon:after {
33 | font-size: 0.75em;
34 | padding-left: 0.5em;content: "\25B2";
35 | }
36 |
37 | /* content panel */
38 |
39 | div[id="content"] {
40 | border: 1px #000 solid;
41 | padding: 1em;
42 | background: #555;
43 | color: #FFF;
44 | }
45 |
--------------------------------------------------------------------------------
/disclosure3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Disclosure button design pattern: <span> element
9 |
10 |
11 |
12 |
13 |
14 |
15 | Disclosure button design pattern: <span>
element
16 |
17 | This disclosure button is created using the <span>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | It is better to use the <button>
element to create a disclosure button because the browser will automatically provide keyboard support and most semantic information.
20 |
21 | Example
22 |
23 |
24 |
Tequila
25 |
26 |
Makes me happy!
27 |
28 |
29 |
30 | Notes
31 |
32 | Uses the HTML tabindex
attribute with a value of 0. This places the <span>
into the tab order based on its location in the source code. The visual appearance of the button changes when focus moves to it.
33 |
34 | Uses the ARIA role
attribute with a value of button . This instructs the browser to expose the <span>
element as a button through its accessibility API. This information is used by assistive technologies to inform users what they're dealing with.
35 |
36 | Keyboard interaction for the button control is handled through scripting. Both enter and space key events are captured, and used to trigger the button's expected behaviour.
37 |
38 | The aria-expanded
attribute is used to indicate the state of the disclosure widget. It is applied to the <span>
so that assistive technologies can determine the state of the widget whether it is expanded or collapsed. The aria-expanded
attribute is set to false (collapsed) initially, then scripted to toggle between true and false whenever the button is activated.
39 |
40 | The aria-controls
attribute is used to create a relationship between the <span>
and the <div>
that contains the content. It takes the idref of the <div>
as its value. This enables assistive technologies to provide specific commands for moving focus from the <span>
to the <div>
.
41 |
42 | The hidden
attribute indicates the state of the <div>
containing the content. It is used to hide the content both visually and from assistive technologies. The hidden
attribute is added initially, then scripted to be added or removed whenever the button is activated.
43 |
44 | The visible style of the <button>
when pressed is hooked to the aria-expanded
attribute. Similarly the visibility of the <div>
is hooked to the aria-hidden
attribute using CSS selectors . This has no direct impact on accessibility, but it creates a cleaner separation between structure and design.
45 |
46 | Note: There is an issue with Firefox, where content with aria-hidden
is exposed to assistive technologies when inside a <button>
or an element with role="button"
applied. Refer to bug 1147359 for more information.
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/disclosure3/js/disclosure.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var button = document.getElementById('button');
5 | var icon = document.getElementById('icon');
6 | var content = document.getElementById('content');
7 |
8 | button.setAttribute('role', 'button');
9 | button.setAttribute('tabindex', 0);
10 | button.setAttribute('aria-expanded', 'false');
11 | icon.setAttribute('aria-hidden', 'true');
12 | content.setAttribute('hidden', 'true');
13 |
14 | function disclose(event) {
15 | if (content.hasAttribute('hidden')) {
16 | button.setAttribute('aria-expanded', 'true');
17 | button.setAttribute('aria-controls', 'content');
18 | content.removeAttribute('hidden');
19 | }
20 | else {
21 | button.setAttribute('aria-expanded', 'false');
22 | content.setAttribute('hidden', 'true');
23 | button.removeAttribute('aria-controls');
24 | }
25 | }
26 |
27 | button.addEventListener('click', disclose, false);
28 |
29 | button.addEventListener('keydown', function(event) {
30 | if (event.keyCode == 13 || event.keyCode ==32) {
31 | disclose();
32 | }
33 | });
34 |
35 | })();
36 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Accessible design patterns
9 |
10 |
11 |
12 |
13 |
14 | Accessible design patterns
15 |
16 | Examples of common custom control and widget design patterns.
17 |
18 | Toggle button design patterns
19 |
24 |
25 | Disclosure button design patterns
26 |
31 |
32 | ToggleTip button design patterns
33 |
37 |
38 | Link design patterns
39 |
42 |
43 | Tabpanel design patterns
44 |
48 |
49 | Live region design patterns
50 |
53 |
54 | Autocomplete design patterns
55 |
58 |
59 | ARIA design patterns
60 |
66 | ***
67 |
68 |
--------------------------------------------------------------------------------
/link1/css/link.css:
--------------------------------------------------------------------------------
1 | span {
2 | color: #009;
3 | background: transparent;
4 | text-decoration: underline;
5 | }
6 |
7 | span:hover, span:focus, span:active {
8 | color:#000;
9 | background-color: #fc0;
10 | cursor: pointer;
11 | }
12 |
--------------------------------------------------------------------------------
/link1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Link design pattern
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Link design pattern
16 |
17 | This link is created using the <span>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | It is better to use the <a>
element because the browser will automatically provide complete functionality (including context menu, URL to status bar, and visited state information), as well as keyboard support and full semantics.
20 |
21 | Example
22 |
23 |
24 | Tink UK
25 |
26 |
27 | Notes
28 |
29 | The tabindex
attribute places the span element into the tab order, based on the element's location within the DOM.
30 |
31 | The link changes appearance with hover and focus.
32 |
33 | The link
role exposes the span as a link in the accessibility tree.
34 |
35 | The click and keydown event listeners capture the expected mouse and keyboard events for activating the link.
36 |
37 |
38 |
--------------------------------------------------------------------------------
/link1/js/link.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | function makeLinks () {
5 |
6 | if (typeof NodeList.prototype.forEach === 'undefined') {
7 | NodeList.prototype.forEach = Array.prototype.forEach;
8 | }
9 |
10 | var links = document.querySelectorAll('[data-link]');
11 |
12 | var fetchResource = function (e) {
13 |
14 | if (e.type === "keydown" && e.keyCode !== 13) {
15 | return false;
16 | }
17 |
18 | e.preventDefault();
19 |
20 | window.location.href = e.target.dataset.link;
21 | };
22 |
23 | links.forEach(function (link) {
24 | link.tabIndex = '0';
25 | link.setAttribute('role', 'link');
26 | link.addEventListener("click", fetchResource);
27 | link.addEventListener("keydown", fetchResource);
28 | });
29 | }
30 |
31 | document.addEventListener('DOMContentLoaded', function () {
32 | makeLinks();
33 | });
34 | })();
35 |
--------------------------------------------------------------------------------
/live1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Live region design pattern
9 |
10 |
11 |
12 |
13 |
14 | Live region design pattern
15 |
16 | This live region is created using the <button>
and <div>
elements, with scripting to provide the expected behaviour. Additional semantic information is provided with ARIA .
17 |
18 | Example
19 |
20 |
21 |
22 |
Basket summary
23 |
24 |
25 |
Your basket contains 0 items.
26 |
27 |
28 |
29 | Add to basket
30 |
31 |
32 |
33 |
34 | Notes
35 |
36 | The aria-live
attribute has been used to convert the <div>
into a live region. The assertive
value means that screen readers will interupt their current activity to notify the user that the content of the live region has changed.
37 |
38 | The aria-atomic
attribute has been used to define how much of the live region content should be announced. The value of true
means that all the content in the live region will be announced, even when only part of the content has been updated.
39 |
40 | Notes on screen reader support for live regions are available.
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/live1/js/liveregion.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | document.getElementById("button").addEventListener("click", updateItems);
5 |
6 | var items = 0;
7 |
8 | function updateItems (e) {
9 | items = items + 1;
10 | document.getElementById("quantity").innerHTML=items;
11 | }
12 | })();
--------------------------------------------------------------------------------
/live1/js/liveregion2.js:
--------------------------------------------------------------------------------
1 | var items = 0;
2 |
3 | function init()
4 | {
5 | document.getElementById("button").addEventListener("click", updateItems);
6 | }
7 |
8 | function updateItems(event)
9 | {
10 | items = items + 1;
11 | document.getElementById("quantity").innerHTML=items;
12 | }
13 |
14 | window.onload = init;
--------------------------------------------------------------------------------
/live2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Live region design pattern
9 |
10 |
11 |
12 |
13 |
14 | Live region design pattern
15 |
16 | This live region is created using the <button>
and <div>
elements, with scripting to provide the expected behaviour. Additional semantic information is provided with ARIA .
17 |
18 | Example
19 |
20 |
21 |
22 |
Live update
23 |
24 |
25 |
26 |
27 |
28 |
29 | Update
30 |
31 |
32 |
33 |
34 | Notes
35 |
36 | The aria-live
attribute has been used to convert the <div>
into a live region. The assertive
value means that screen readers will interupt their current activity to notify the user that the content of the live region has changed.
37 |
38 | The aria-atomic
attribute has been used to define how much of the live region content should be announced. The value of true
means that all the content in the live region will be announced, even when only part of the content has been updated.
39 |
40 | Notes on screen reader support for live regions are available.
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/live2/js/liveregion.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | document.getElementById("button").addEventListener("click", updateLiveRegion);
5 |
6 | function updateLiveRegion (e) {
7 | var update = document.getElementById("update");
8 | update.innerHTML = "";
9 | setTimeout(function(){ update.innerHTML = "Successfully updated!";}, 100);
10 | }
11 | } )();
--------------------------------------------------------------------------------
/live2/js/liveregion2.js:
--------------------------------------------------------------------------------
1 | var items = 0;
2 |
3 | function init()
4 | {
5 | document.getElementById("button").addEventListener("click", updateItems);
6 | }
7 |
8 | function updateItems(event)
9 | {
10 | items = items + 1;
11 | document.getElementById("quantity").innerHTML=items;
12 | }
13 |
14 | window.onload = init;
--------------------------------------------------------------------------------
/svg-flowchart/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SVG flowchart design pattern
5 |
6 |
7 |
8 | SVG flowchart design pattern
9 |
10 | The flowchart from the W3C Process 2018 , as described in Accessible SVG flowcharts.
11 |
12 |
220 |
221 |
222 |
223 |
224 |
--------------------------------------------------------------------------------
/svg-line-graph/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SVG line graph design pattern
5 |
6 |
24 |
25 |
26 |
27 | SVG line graph design pattern
28 |
29 | Demo from this accessible SVG line graph post.
30 |
31 |
32 | WebAIM screen reader survey: results 2009 to 2015
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | 0
80 | 25
81 | 50
82 | 75
83 | 100
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | Percentage usage
98 |
99 |
100 |
101 |
102 |
103 | Time
104 | Jan 2009
105 | Dec 2010
106 | May 2012
107 | Jan 2014
108 | Jul 2015
109 |
110 |
111 |
112 |
113 |
114 |
115 | Jaws
116 |
117 |
118 |
119 |
120 |
121 | 74%
122 |
123 |
124 |
125 |
126 |
127 | 69.6%
128 |
129 |
130 |
131 |
132 |
133 | 63.7%
134 |
135 |
136 |
137 |
138 |
139 | 63.9%
140 |
141 |
142 |
143 |
144 |
145 | 43.7%
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | NVDA
154 |
155 |
156 |
157 |
158 |
159 | 8%
160 |
161 |
162 |
163 |
164 |
165 | 34.8%
166 |
167 |
168 |
169 |
170 |
171 | 43%
172 |
173 |
174 |
175 |
176 |
177 | 51.2%
178 |
179 |
180 |
181 |
182 |
183 | 41.4%
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 | VoiceOver
192 |
193 |
194 |
195 |
196 |
197 | 6%
198 |
199 |
200 |
201 |
202 |
203 | 20.2%
204 |
205 |
206 |
207 |
208 |
209 | 30.7%
210 |
211 |
212 |
213 |
214 |
215 | 36.8%
216 |
217 |
218 |
219 |
220 |
221 | 30.9%
222 |
223 |
224 |
225 |
226 |
227 | Desktop screen reader use: 2009 to 2015
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 | Jaws
236 |
237 |
238 |
239 |
240 |
241 | NVDA
242 |
243 |
244 |
245 |
246 |
247 | VoiceOver
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
261 |
262 |
263 |
--------------------------------------------------------------------------------
/svg-line-graph/original.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SVG line graph
5 |
6 |
24 |
25 |
26 |
27 | SVG graph
28 |
29 | An accessible version is available .
30 |
31 |
32 | WebAIM screen reader survey: results 2009 to 2015
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | 0
80 | 25
81 | 50
82 | 75
83 | 100
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | Percentage usage
98 |
99 |
100 |
101 | Time
102 | Jan 2009
103 | Dec 2010
104 | May 2012
105 | Jan 2014
106 | Jul 2015
107 |
108 |
109 |
110 | Jaws
111 |
112 |
113 |
114 | 74%
115 |
116 |
117 |
118 | 69.6%
119 |
120 |
121 |
122 | 63.7%
123 |
124 |
125 |
126 | 63.9%
127 |
128 |
129 |
130 | 43.7%
131 |
132 |
133 |
134 |
135 | NVDA
136 |
137 |
138 |
139 | 8%
140 |
141 |
142 |
143 | 34.8%
144 |
145 |
146 |
147 | 43%
148 |
149 |
150 |
151 | 51.2%
152 |
153 |
154 |
155 | 41.4%
156 |
157 |
158 |
159 |
160 | VoiceOver
161 |
162 |
163 |
164 | 6%
165 |
166 |
167 |
168 | 20.2%
169 |
170 |
171 |
172 | 30.7%
173 |
174 |
175 |
176 | 36.8%
177 |
178 |
179 |
180 | 30.9%
181 |
182 |
183 |
184 |
185 |
186 | Desktop screen reader use: 2009 to 2015
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | Jaws
196 |
197 |
198 |
199 |
200 |
201 | NVDA
202 |
203 |
204 |
205 |
206 |
207 | VoiceOver
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/tabpanels1/css/tabpanels.css:
--------------------------------------------------------------------------------
1 | .tab {
2 | // placeholder
3 | }
4 |
5 | .selected {
6 | // placeholder
7 | }
8 |
9 | ul#tabs li {
10 | display: inline;
11 | }
12 | /*
13 | ul#tabs li:hover {
14 | background-color: red;
15 | }
16 | */
17 |
18 | ul#tabs li a.selected {
19 | background-color: #ddd;
20 | }
21 |
22 | ul#tabs li a {
23 | text-decoration: none;
24 | color: #000;
25 | border-top: solid black thin;
26 | border-left: solid black thin;
27 | border-right: solid black thin;
28 | padding: 1em 1em 0 1em;
29 | font-weight: 700;
30 | }
31 |
32 | ul#tabs li a:hover, ul#tabs li a:focus {
33 | background-color: blue;
34 | color: #fff;
35 | outline: 0;
36 | }
37 |
38 | ul#tabs {
39 | margin: 0;
40 | padding: 0;
41 | }
42 |
43 | .tabcontent {
44 | display: block;
45 | border: solid black thin;
46 | padding: 1em;
47 | }
48 |
49 | .hidden {
50 | display: none;
51 | }
52 |
--------------------------------------------------------------------------------
/tabpanels1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Tabpanels with ARIA design pattern
9 |
10 |
11 |
12 |
13 |
66 |
67 |
68 |
69 | Tabpanels with ARIA design pattern
70 |
71 | These tabpanels are created using the <ul>
, <li>
, and <div>
elements, with scripting to provide the expected behaviour. Additional semantic information is provided with ARIA .
72 |
73 | Example
74 |
75 |
76 |
81 |
82 |
83 |
Blanco tequila is...
84 |
85 |
86 |
87 |
Reposado tequila is...
88 |
89 |
90 |
91 |
Jovan tequila is...
92 |
93 |
94 |
95 |
96 | Notes
97 |
98 | The tablist
, tab
, and tabpanel
roles expose the <ul>
, <a>
, and <div>
elements as a collection of tabs and corresponding tabpanels in the accessibility tree.
99 |
100 | The presentation
role prevents the <li>
elements from being mapped in the accessibility tree.
101 |
102 | The aria-selected
attribute indicates which tab is currently selected.
103 |
104 | The tabindex
attribute ensures that only the currently selected tab is included in the tab order.
105 |
106 | The hidden
attribute hides all but the currently displayed tabpanel from view.
107 |
108 | The aria-controls
attribute establishes a relationship between each tab and its corresponding tabpanel.
109 |
110 | The aria-labelledby
attribute reuses the name of the tab as the accessible name of the corresponding tabpanel.
111 |
112 | The click
and keydown
event listeners capture the expected mouse and keyboard events for activating the tabs.
113 |
114 |
115 |
--------------------------------------------------------------------------------
/tabpanels2/css/tabpanels.css:
--------------------------------------------------------------------------------
1 | .tab {
2 | // placeholder
3 | }
4 |
5 | .selected {
6 | // placeholder
7 | }
8 |
9 | ul#tabs li {
10 | display: inline;
11 | }
12 | /*
13 | ul#tabs li:hover {
14 | background-color: red;
15 | }
16 | */
17 |
18 | ul#tabs li a.selected {
19 | background-color: #ddd;
20 | }
21 |
22 | ul#tabs li a {
23 | text-decoration: none;
24 | color: #000;
25 | border-top: solid black thin;
26 | border-left: solid black thin;
27 | border-right: solid black thin;
28 | padding: 1em 1em 0 1em;
29 | font-weight: 700;
30 | }
31 |
32 | ul#tabs li a:hover, ul#tabs li a:focus {
33 | background-color: blue;
34 | color: #fff;
35 | outline: 0;
36 | }
37 |
38 | ul#tabs {
39 | margin: 0;
40 | padding: 0;
41 | }
42 |
43 | .tabcontent {
44 | display: block;
45 | border: solid black thin;
46 | padding: 1em;
47 | }
48 |
49 | .hidden {
50 | display: none;
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/tabpanels2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Tabpanels without ARIA design pattern
9 |
10 |
11 |
12 |
13 |
64 |
65 |
66 |
67 | Tabpanels without ARIA design pattern
68 |
69 | These tabpanels are created using the <ul>
, <li>
, and <div>
elements, with scripting to provide the expected behaviour. No additional semantic information has been provided using ARIA.
70 |
71 | Example
72 |
73 |
74 |
75 |
80 |
81 |
82 |
Blanco tequila is...
83 |
84 |
85 |
86 |
Reposado tequila is...
87 |
88 |
89 |
90 |
Jovan tequila is...
91 |
92 |
93 |
94 |
95 | Notes
96 |
97 | Despite looking like a set of tabs, screen readers treat the underlying structure as a list of "same page" anchor links, followed by a chunk of unassociated content.
98 |
99 |
100 |
--------------------------------------------------------------------------------
/toggle1/css/button.css:
--------------------------------------------------------------------------------
1 | button {
2 | display: block;
3 | height: 35px;
4 | width: 100px;
5 | font-size: 1.1em;
6 | font-weight: bold;
7 | padding: 10px 15px;
8 | margin: 20px auto;
9 | color: #ccc;
10 | background-color: #555;
11 | border: 0 none;
12 | border-radius: 3px;
13 | text-shadow: 0 -1px 0 #000;
14 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
15 | }
16 |
17 | button:hover, button:focus {
18 | background-color: #820bbb;
19 | }
20 |
21 | [aria-pressed="true"] {
22 | color: #fff;
23 | padding: 11px 12px 9px 16px;
24 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
25 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
26 | }
27 |
--------------------------------------------------------------------------------
/toggle1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Toggle button design pattern: <button> element
9 |
10 |
11 |
12 |
13 |
14 |
15 | Toggle button design pattern: <button>
element
16 |
17 | This toggle button is created using the <button>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | Example
20 |
21 |
22 | Tequila!
23 |
24 |
25 | Notes
26 |
27 | Keyboard focus and interaction is handled automatically by the browser, and the button can be activated using either the enter or space key.
28 |
29 | The aria-pressed attribute is used to indicate the state of the button. It is set to false initially, then scripted to toggle between true/false whenever the button is activated.
30 |
31 | The visual appearance of the button when pressed (or not) is hooked onto the aria-pressed attribute using an intelligent CSS selector , instead of a class name. Although this does not affect accessibility, it creates a cleaner separation between structure and design.
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/toggle1/js/button.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var button = document.getElementById('button');
5 | button.setAttribute('aria-pressed', 'false');
6 |
7 | function toggle(event) {
8 | if (button.getAttribute('aria-pressed') == 'false') {
9 | button.setAttribute('aria-pressed', 'true');
10 | }
11 | else {
12 | button.setAttribute('aria-pressed', 'false');
13 | }
14 | }
15 |
16 | button.addEventListener('click', toggle, false);
17 |
18 | })();
19 |
20 |
--------------------------------------------------------------------------------
/toggle2/css/button.css:
--------------------------------------------------------------------------------
1 | a[id="button"],a[id="button"]:visited {
2 | display: block;
3 | height: 15px;
4 | width: 65px;
5 | font-size: 1.1em;
6 | font-weight: bold;
7 | padding: 10px 15px;
8 | margin: 20px auto;
9 | color: #ccc;
10 | background-color: #555;
11 | border: 0 none;
12 | border-radius: 3px;
13 | text-decoration: none;
14 | text-shadow: 0 -1px 0 #000;
15 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
16 | }
17 |
18 | a[id="button"]:hover, a[id="button"]:focus {
19 | background-color: #820bbb;
20 | }
21 |
22 | a[aria-pressed="true"],a[aria-pressed="true"]:visited {
23 | color: #fff;
24 | padding: 11px 12px 9px 16px;
25 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
26 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
27 | }
28 |
--------------------------------------------------------------------------------
/toggle2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Toggle button design pattern: <a> element
9 |
10 |
11 |
12 |
13 |
14 |
15 | Toggle button design pattern: <a>
element
16 |
17 | This toggle button is created using the <a>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | It is better to use the <button>
element to create a toggle button because the browser automatically provides keyboard support and most semantic information.
20 |
21 | Example
22 |
23 |
26 |
27 | Notes
28 |
29 | Uses the ARIA role attribute with a value of button . This informs the browser that it should expose the <a>
element as a button through its accessibility API. This information is utilised by assistive technologies to inform users what they're dealing with.
30 |
31 | Keyboard focus is handled by the browser because <a>
is an interactive element .
32 |
33 | Keyboard interaction is handled by the browser and through scripting. The <a>
element can be activated with the Enter key and the button inherits this behaviour. The ability to activate the button using the space key is provided through scripting.
34 |
35 | The aria-pressed attribute is used to indicate the state of the button. It is set to false initially, then scripted to toggle between true/false whenever the button is activated.
36 |
37 | The visual appearance of the button when pressed (or not) is hooked onto the aria-pressed attribute using an intelligent CSS selector , instead of a class name. Although this does not affect accessibility, it creates a cleaner separation between structure and design.
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/toggle2/js/button.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var button = document.getElementById('button');
5 | button.setAttribute('role', 'button');
6 | button.setAttribute('tabindex', 0);
7 | button.setAttribute('aria-pressed', 'false');
8 |
9 | function toggle(event) {
10 | if (button.getAttribute('aria-pressed') == 'false') {
11 | button.setAttribute('aria-pressed', 'true');
12 | }
13 | else {
14 | button.setAttribute('aria-pressed', 'false');
15 | }
16 | }
17 |
18 | button.addEventListener('click', toggle, false);
19 |
20 | button.addEventListener('keydown', function(event) {
21 | if (event.keyCode ==13) {
22 | toggle();
23 | }
24 | });
25 |
26 | })();
27 |
28 |
--------------------------------------------------------------------------------
/toggle3/css/button.css:
--------------------------------------------------------------------------------
1 | span[id="button"] {
2 | display: block;
3 | height: 15px;
4 | width: 65px;
5 | font-size: 1.1em;
6 | font-weight: bold;
7 | padding: 10px 15px;
8 | margin: 20px auto;
9 | color: #ccc;
10 | background-color: #555;
11 | border: 0 none;
12 | border-radius: 3px;
13 | text-shadow: 0 -1px 0 #000;
14 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
15 | }
16 |
17 | span[id="button"]:hover, span[id="button"]:focus {
18 | background-color: #820bbb;
19 | }
20 |
21 | span[aria-pressed="true"] {
22 | color: #fff;
23 | padding: 11px 12px 9px 16px;
24 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
25 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
26 | }
27 |
--------------------------------------------------------------------------------
/toggle3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Toggle button design pattern: <span> element
9 |
10 |
11 |
12 |
13 |
14 |
15 | Toggle button design pattern: <span>
element
16 |
17 | This toggle button is created using the <span>
element, with scripting to provide the expected behaviour. Additional semantic information is provided using ARIA .
18 |
19 | It is better to use the <button>
element to create a toggle button because the browser automatically provides keyboard support and most semantic information.
20 |
21 | Example
22 |
23 |
24 | Tequila!
25 |
26 |
27 | Notes
28 |
29 | Uses the ARIA role attribute with a value of button . This informs the browser that it should expose the <span>
element as a button through its accessibility API. This information is utilised by assistive technologies to inform users what they're dealing with.
30 |
31 | Uses the HTML tabindex attribute with a value of 0. This places the button into the tab order based on its location in the source order. The visual appearance of the button changes when focus moves to it.
32 |
33 | Keyboard interaction for the button is handled through scripting. Both enter and space key events are captured, and used to trigger the button's expected behaviour.
34 |
35 | The aria-pressed attribute is used to indicate the state of the button. It is set to false initially, then scripted to toggle between true/false whenever the button is activated.
36 |
37 | The visual appearance of the button when pressed (or not) is hooked onto the aria-pressed attribute using an intelligent CSS selector , instead of a class name. Although this does not affect accessibility, it creates a cleaner separation between structure and design.
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/toggle3/js/button.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var button = document.getElementById('button');
5 | button.setAttribute('role', 'button');
6 | button.setAttribute('tabindex', 0);
7 | button.setAttribute('aria-pressed', 'false');
8 |
9 | function toggle(event) {
10 | if (button.getAttribute('aria-pressed') == 'false') {
11 | button.setAttribute('aria-pressed', 'true');
12 | }
13 | else {
14 | button.setAttribute('aria-pressed', 'false');
15 | }
16 | }
17 |
18 | button.addEventListener('click', toggle, false);
19 |
20 | button.addEventListener('keydown', function(event) {
21 | if (event.keyCode == 13 || event.keyCode ==32) {
22 | toggle();
23 | }
24 | });
25 |
26 | })();
27 |
28 |
--------------------------------------------------------------------------------
/toggletip1/css/toggletip.css:
--------------------------------------------------------------------------------
1 | button {
2 | display: block;
3 | height: 35px;
4 | width: 100px;
5 | font-size: 1.1em;
6 | font-weight: bold;
7 | padding: 10px 15px;
8 | color: #ccc;
9 | background-color: #555;
10 | border: 0 none;
11 | border-radius: 3px;
12 | box-shadow: 0 1px 0 #666, 0 5px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
13 | }
14 |
15 | button:hover, button:focus {
16 | background-color: #820bbb;
17 | color: #fff;
18 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
19 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
20 | cursor: pointer;
21 | }
22 |
23 | [aria-expanded"true"] {
24 | color: #fff;
25 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
26 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
27 | }
28 |
29 | aside span{
30 | z-index:99;
31 | display: block;
32 | background: #eee;
33 | border: 1px solid #ccc;
34 | padding: 10px;
35 | border-radius: 8px;
36 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
37 | position: absolute;
38 | width: 14m;
39 | }
40 |
--------------------------------------------------------------------------------
/toggletip1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Toggletip design pattern
9 |
10 |
11 |
12 |
13 |
14 |
15 | Toggletip design pattern
16 |
17 |
20 |
21 |
22 |
23 |
Tequila
24 |
25 |
28 |
29 |
30 |
31 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/toggletip1/js/toggletip.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var button = document.getElementById('button');
4 | var tip = document.getElementById('tip');
5 | var content = document.getElementById('content');
6 |
7 | button.setAttribute('aria-expanded', 'false');
8 | button.setAttribute('aria-describedby', 'tip');
9 |
10 | tip.setAttribute('hidden', true);
11 |
12 | content.setAttribute('role', 'tooltip');
13 | content.setAttribute('aria-live', 'polite');
14 |
15 | function toggleTip(e) {
16 |
17 | if (tip.hasAttribute('hidden')) {
18 | button.setAttribute('aria-expanded', 'true');
19 | content.innerHTML = "Tequila (makes me happy)!";
20 | tip.removeAttribute('hidden');
21 | } else {
22 | button.setAttribute('aria-expanded', 'false');
23 | content.innerHTML = '';
24 | tip.setAttribute('hidden', true);
25 | }
26 | }
27 |
28 | button.addEventListener('click', toggleTip, false);
29 |
30 | document.addEventListener('keydown', function(e) {
31 |
32 | if (e.keyCode == 27) {
33 | toggleTip();
34 | }
35 | });
36 |
37 | })();
38 |
--------------------------------------------------------------------------------
/toggletip1/js/toggletip.js~:
--------------------------------------------------------------------------------
1 | var tip = document.getElementById('tip');
2 | var button = document.getElementById('button');
3 |
4 | button.setAttribute('aria-expanded', 'false');
5 | button.setAttribute('aria-describedby', 'tip');
6 |
7 | tip.setAttribute('hidden', true);
8 |
9 | function showTip() {
10 | button.setAttribute('aria-expanded', 'true');
11 |
12 | tip.innerHTML = " Tequila (makes me happy)! ";
13 | tip.removeAttribute('hidden');
14 | }
15 |
16 | function hideTip() {
17 | button.setAttribute('aria-expanded', 'false');
18 |
19 | tip.innerHTML = '';
20 | tip.setAttribute('hidden', true);
21 | }
22 |
23 | function toggleTip(e) {
24 |
25 | if (tip.hasAttribute('hidden')) {
26 | showTip();
27 | } else {
28 | hideTip();
29 | }
30 | }
31 |
32 | button.addEventListener('click', toggleTip, false);
33 |
34 | document.addEventListener('keyup', function(e) {
35 |
36 | if (e.keyCode == 27) {
37 | toggleTip();
38 | }
39 | });
40 |
--------------------------------------------------------------------------------
/toggletip2/css/toggletip.css:
--------------------------------------------------------------------------------
1 | span[id="button"] {
2 | display: block;
3 | height: 15px;
4 | width: 60px;
5 | font-size: 1.1em;
6 | font-weight: bold;
7 | padding: 10px 15px;
8 | color: #ccc;
9 | background-color: #555;
10 | border: 0 none;
11 | border-radius: 3px;
12 | box-shadow: 0 1px 0 #666, 0 5px 0 #444, 0 6px 6px rgba(0,0,0,0.6);
13 | }
14 |
15 | span[id="button"]:hover, span[id="button"]:focus {
16 | background-color: #820bbb;
17 | color: #fff;
18 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
19 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
20 | cursor: pointer;
21 | }
22 |
23 | [aria-expanded"true"] {
24 | color: #fff;
25 | text-shadow: 0 -1px 0 #444, 0 0 5px #ffd, 0 0 8px #fff;
26 | box-shadow: 0 1px 0 #666, 0 2px 0 #444, 0 2px 2px rgba(0,0,0,0.9);
27 | }
28 |
29 | span[role="tooltip"] {
30 | z-index:99;
31 | display: block;
32 | background: #eee;
33 | border: 1px solid #ccc;
34 | padding: 10px;
35 | border-radius: 8px;
36 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
37 | position: absolute;
38 | width: 14m;
39 | }
40 |
--------------------------------------------------------------------------------
/toggletip2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Toggletip design pattern (div/span)
9 |
10 |
11 |
12 |
13 |
14 |
15 | Toggletip design pattern (div/span)
16 |
17 | This toggletip is created using the <span>
and <div>
elements, with scripting to provide the expected behaviour. Additional semantic information is provided with ARIA .
18 |
19 | It is better to use the <button>
and <aside>
elements to create toggletips because the browser provides more keyboard support and semantic information.
20 |
21 |
22 | Example
23 |
24 |
25 |
26 |
Tequila
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Notes
35 |
36 | This toggletip is based on the design pattern first proposed by Steve Faulkner .
37 |
38 | The button
role is used to expose the <span>
element as a button in the accessibility tree.
39 |
40 | The tabindex
attribute is used to add the <span>
element to the tab order, based on its location within the DOM.
41 |
42 | The complementary
role is used to expose the <div>
element as complementary information in the accessibility tree.
43 |
44 | The aria-expanded
attribute indicates the current state of the toggletip.
45 |
46 | The aria-describedby
attribute associates the tooltip content with the <button>
.
47 |
48 | The hidden
attribute hides the <aside>> element until the toggletip is activated.
49 |
50 | The tooltip
role exposes the <span>
element as a tooltip in the accessibility tree.
51 |
52 | The aria-live
attribute turns the <span>
element into a live region that is announced automatically by screen readers.
53 |
54 | The click
and keydown
event listeners capture the expected mouse and keyboard events for opening and closing the toggletip.
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/toggletip2/js/toggletip.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var tip = document.getElementById('tip');
4 | var button = document.getElementById('button');
5 | var content = document.getElementById('content');
6 |
7 | button.setAttribute('role', 'button');
8 | button.setAttribute('tabindex', '0');
9 | button.setAttribute('aria-expanded', 'false');
10 | button.setAttribute('aria-describedby', 'tip');
11 |
12 | tip.setAttribute('role', 'complementary');
13 | tip.setAttribute('hidden', true);
14 |
15 | content.setAttribute('role', 'tooltip');
16 | content.setAttribute('aria-live', 'polite');
17 |
18 | function toggleTip(e) {
19 |
20 | if (tip.hasAttribute('hidden')) {
21 | button.setAttribute('aria-expanded', 'true');
22 | content.innerHTML = "Makes me happy!";
23 | tip.removeAttribute('hidden');
24 | } else {
25 | button.setAttribute('aria-expanded', 'false');
26 | content.innerHTML = '';
27 | tip.setAttribute('hidden', true);
28 | }
29 | }
30 |
31 | button.addEventListener('click', toggleTip, false);
32 |
33 | button.addEventListener('keydown', function(e) {
34 |
35 | if (e.keyCode == 13 || e.keycode == 32) {
36 | toggleTip();
37 | }
38 | });
39 |
40 | document.addEventListener('keydown', function(e) {
41 |
42 | if (e.keyCode == 27) {
43 | toggleTip();
44 | }
45 | });
46 |
47 | })();
48 |
--------------------------------------------------------------------------------