-
Notifications
You must be signed in to change notification settings - Fork 34
/
index.html
323 lines (276 loc) · 15.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<title>Switch Component: Checkbox</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
// remove no-js and add 'js' to the HTML
document.documentElement.className = document.documentElement.className.replace('no-js', 'js');
</script>
<link rel="stylesheet" href="../assets/css/--demo-only--.css">
<link rel="stylesheet" href="../assets/css/--shared--.css">
<link rel="stylesheet" href="../assets/css/switch--checkbox.css">
<link rel="stylesheet" href="../assets/css/switch--checkbox--alt.css">
</head>
<body>
<div class="demo-wrap">
<header class="demo-wrap__header">
<p class="demo-wrap__header__title">
Accessible Styled Form Controls
</p>
<nav>
<a href="https://github.com/scottaohara/a11y_styled_form_controls">See source on GitHub</a>,
<a href="/a11y_styled_form_controls">Index of styled form controls</a>
</nav>
</header>
<main aria-label="content">
<div class="demo">
<div>
<h1>Switch Component: Checkbox</h1>
<p>Published: <time>July 26, 2018</time></p>
<p>Last updated: May 11, 2021</p>
<p>
Pattern to modify a <code>checkbox</code> into a <code>switch</code> component.
</p>
</div>
<h2>
Pattern Demo
</h2>
<form>
<p style="margin-bottom: .25em">
Version: <code>[type="checkbox"]</code> styled to look like a switch
</p>
<label class="check-switch" for="switch_1">
Example Text 1:
<input type="checkbox" id="switch_1">
<span aria-hidden="true"></span>
</label>
<p style="margin-bottom: .25em">
Version: <code>[type="checkbox"][role="switch"]</code>
</p>
<label class="check-switch" for="switch_2">
Example Text 2:
<input type="checkbox" id="switch_2" data-check-switch>
<span aria-hidden="true"></span>
</label>
<p style="margin-bottom: .25em">
Version: <code>[type="checkbox"][role="switch"]</code> - Alternate Markup/Style
</p>
<!--
Based on pattern by Richard Keizer: https://codepen.io/rakeizer/pen/QQRBoZ
-->
<div class="switchbox">
<label for="switchbox">
Example Text 3:
</label>
<input type="checkbox" id="switchbox" data-check-switch>
</div>
</form>
<details style="margin-top: 1em;">
<summary>Visual design notes</summary>
<div>
<p>These notes were last updated in August 2020.</p>
<p>
<code>-moz-appearance: none;</code> did not completely remove the styling in earlier versions of Firefox. But it should work as expected in Firefox 60+.
</p>
<p>
The <code>box-shadow</code> to provide an outline of the control does not
render as expected in IE11, did work as expected in Edge (legacy).
</p>
<p>
IE and Edge (legacy) don't respect the box-shadow in High Contrast mode.
Previously, the <code>::-ms-check</code> was re-enabled so that people will at least see
a checkmark when the switch is on, and an empty oval when off. Chromium Edge does respect the
box-shadow fill, so this has been updated. I no longer have Legacy Edge to verify if
this introduces an issue there or not.
</p>
</div>
</details>
<section class="demo-details">
<h3>
Pattern Details
</h3>
<details open>
<summary>Pattern Markup</summary>
<pre><code class="language-html"><!-- Version: [type="checkbox"] styled to look like a switch -->
<label class="check-switch" for="switch_1">
Example Text 1:
<input id="switch_1" type="checkbox">
<span aria-hidden="true"></span>
</label>
<!-- Version: [type="checkbox"][role="switch"] -->
<label class="check-switch" for="switch_2">
Example Text 2:
<input id="switch_2" data-check-switch="" role="switch" type="checkbox">
<span aria-hidden="true"></span>
</label>
<!-- Version: [type="checkbox"][role="switch"] - Alternate Markup/Style -->
<div class="switchbox">
<label for="switchbox">
Example Text 3:
</label>
<input id="switchbox" data-check-switch="" role="switch" type="checkbox">
</div></code></pre>
</details>
<p>
Similar to the <a href="../checkbox/index.html">styled checkbox pattern</a>, an <code>input type=checkbox</code> can be used to create a custom switch control. A <code>switch</code> and <code>checkbox</code> behave similarly.
</p>
<p>As the ARIA specification notes:</p>
<blockquote>
A <code>switch</code> provides approximately the same functionality as a <code>checkbox</code> and toggle <code>button</code>, but makes it possible for assistive technologies to present the widget in a fashion consistent with its on-screen appearance.
</blockquote>
<p>
That said, a <code>switch</code> can often be found in "settings" UI, where toggling the switch's state can immediately cause a function or state change to occur. A checkboxes are commonly used (have a very long history) within forms – where toggling its state is not expected to result in an immediate function until the form itself is submitted. That's not to say that toggling checkboxes cannot also be used to cause an immediate action to occur. For instance, using checkboxes as controls to filter search results on an e-commerce site. But, this is not an "official" difference between the controls – more just me trying to point to common use to indicate a reason as to why the heck we'd need two toggle controls aside from aesthetic reasons...</p>
<p>
That all said, if implementing visually styled switches within your project, their implementation should be consistent across instances. Meaning that if a checkbox is visually designed to look like a switch (but continued to be announced as a checkbox), then there should be no instances where the same design is used for a <code>role="switch"</code>. This would create confusion in why two similar looking controls are announced differently (for sighted users who also may use screen readers), or perform actions immediately or delayed until form submission.
</p>
<h4>The JavaScript</h4>
<p>
There is little JavaScript that is needed for this component, but what is there is largely for progressive enhancement purposes.
</p>
<p>
Using the <code>data-check-switch</code> attribute as a hook, an <code>input</code> with this attribute will receive a <code>role="switch"</code> when the script runs. Without JavaScript, it will announce itself as a checkbox.
</p>
<p>
The script also allows for the <kbd>Enter</kbd> key to be used to toggle the state of the switch, as checkboxes would otherwise only allow for the <kbd>Space</kbd> key to toggle their state.
</p>
<h4 id="affects_on_sr" tabindex="-1">Affects on Screen Reader Announcements?</h4>
<p>
Giving the <code>input type="checkbox"</code> a <code>role="switch"</code> announces the form control as a "switch", "toggle button" or continues to announce the control as a "checkbox" depending on the screen reader and platform in question.
</p>
<p>
The following is a break down of how this is handled by modern browsers and screen reader pairings.
</p>
<dl>
<dt>
Firefox 88.0.1
</dt>
<dd>With VoiceOver on macOS 11.2.3: announces "switch" role and initial state. Activating the switch will produce a "clicking" noise, but no "on" or "off" announcement is explicitly made.</dd>
<dd>With NVDA 2020.4: announces "checkbox" role and initial state. Activating the 'switch' will announce the new state ("checked" or "not checked").
</dd>
<dd>With JAWS 2020: announces "switch" role and initial state. Activating the switch will announce the new state ("on" or "off").</dd>
<dd>With TalkBack Android 11: announces "switch" role and initial state. Activating the switch will produce a sound effect, and the new state ("checked", "not checked") will be announced, oddly followed by a "loading" announcement.</dd>
<dt>
Chrome / Edge 90
</dt>
<dd>With VoiceOver on macOS 11.2.3: announces "switch" role and initial state. Activating the switch will produce a "clicking" noise and the new state ("on" or "off") will be announced.</dd>
<dd>With NVDA 2020.4: announces "checkbox" role and initial state. Activating the 'switch' will announce the new state ("checked" or "not checked").
</dd>
<dd>With JAWS 2020: announces "switch" role and initial state. Activating the switch will announce the new state ("on" or "off"). When switching to the "on" state, JAWS will announce "pressed on". JAWS does not announce "pressed" when changing to the "off" state.</dd>
<dd>With TalkBack Android 11: announces "switch" role and initial state. Activating the switch will produce a sound effect, and the new state ("checked", "not checked") will be announced.</dd>
<dt>
Edge 90
</dt>
<dd>With Narrator: announces "switch" role and initial state. Activating the switch will announce the new state ("on" or "off"), along with a repeat of the switch's accessible name.</dd>
<dt>
Safari
</dt>
<dd>With VoiceOver on macOS 11.2.3 (Safari 14.0.3): announces "switch" role and initial state. Activating the switch will produce a "clicking" noise and the new state ("on" or "off") will be announced, along with a repeat of the switch's accessible name. </dd>
<dd>With VoiceOver on iOS 14.4.2: announces as "checkbox" role and initial state. Activating will produce a "clicking" noise and the new state ("checked" or "unchecked") will be announced.</dd>
</dl>
<h4>Usage note:</h4>
<p>
Things have improved with switches since my initial testing of this role back in 2018, where state announcements were quirky if not missing all together (archived testing results below). NVDA and iOS Safari/VoiceOver are the hold outs on respecting the <code>switch</code> role, but at least these announce the switch as a checkbox with proper states.
</p>
<details>
<summary>Archived Screen Reader Breakdowns</summary>
<dl>
<dt>JAWS 2020 + Firefox 77 & Chrome and Edge 83</dt>
<dd>
<p>Announces as a "switch". Each announce "on" and "off" when toggling state. Chrome alone will announce "pressed on" for the on state.
</dd>
<dt>Narrator & Edge (legacy)</dt>
<dd>
<p>Announces as a "toggle switch". Announces "on" and "off" when toggling state.</p>
</dd>
<dt>VoiceOver + Safari on iOS 12.2</dt>
<dd>
<p>
iOS VoiceOver continues to announce <code>role="switch"</code> as a "checkbox". However, with the release of iOS 12.2 (Mach 2019) the announcement of state has been fixed and "switches" will announce a "checked" or "unchecked" state.
</p>
<p>
Until iOS 12.2+ has wide adoption, one should still be wary of using <code>role="switch"</code>.
</p>
</dd>
<dt>VoiceOver + Safari on iOS 11.3 (at least) through 12.1.4</dt>
<dd>
<p>
iOS VoiceOver doesn't understand <code>role="switch"</code> and will fallback to announcing the component as a "checkbox". However, this fallback is bugged, as the state of the checkbox will not be announced to users on toggle of the component.
</p>
</dd>
<dt>Narrator & NVDA 2018.4.1 + IE11</dt>
<dd>
<p>This pairing will ignore the <code>role="switch"</code>, and continue to announce the component as a checkbox. Checkbox state will be accurately announced on toggle.</p>
</dd>
<dt>JAWS 2018, 2019, 2020 + IE11</dt>
<dd>
<p>This pairing will announce the form control as a <code>role="switch"</code>, but is inconsistent with announcing the state of the component. Largely only announcing state on a user first focusing the form control with by the virtual cursor navigation or <kbd>tab</kbd> key. If activating the form control repeatedly, focus will be lost and return to an element higher up in the DOM.</p>
</dd>
<dt>NVDA 2020.1 + Firefox 77, IE11, Chrome 82 and Edge 83</dt>
<dd><p><code>role="switch"</code> is ignored and the control is announced as a checkbox. State is accurately announced in regards to being announced as a checkbox.</p></dd>
<dt>NVDA 2018.4.1 + Chrome 72</dt>
<dd>
<p><code>role="switch"</code> is announced as a "toggle button." Toggling announces as "pressed checked" and "not pressed" for their respective states.</p>
</dd>
<dt>NVDA 2018.4.1 & 2019.1beta + Firefox 65.0.1</dt>
<dd>
<p><code>role="switch"</code> is announced as a "toggle button." Toggling announces as "checked" and "not checked" for their respective states.</p>
<p>If "pressed" NVDA will announce initial state as "toggle button not pressed, checked". Toggling state will only announce "not checked" and "checked". (<a href="https://github.com/nvaccess/nvda/issues/9187">Closed bug</a> where apparently NVDA decided to forgo announcing <code>role=switch</code> and expose it as a checkbox.)
</dd>
<dt>
TalkBack 7.2 (on Android 8.1) + Firefox 64.0.2 & Chrome 71
</dt>
<dd>
<p>
Announces as a "switch." Toggling announces as "checked" and "not checked" for their respective states.</p>
</p>
</dd>
</dl>
<details>
<summary>NVDA 2018.1 and 2018.2.1 notes</summary>
<p>
These versions of NVDA paired with FireFox and Chrome will announce elements with <code>role="switch"</code> as "not pressed" and then announce whether they are checked or not.</p>
<p>
It doesn't matter the current state of whether the switch is checked or not, with this version of NVDA the switch would always announce "not pressed."
</p>
<p>
This issue appears to have been fixed after testing with NVDA 2018.4.1.
</p>
</details>
</details>
<h3>Continue Reading</h3>
<p>
For an alternate minimal pattern to create switch checkboxes,
and support for intermediate state, check out
<a href="https://codepen.io/aardrian/pen/WPWVvw">Adrian Roselli's Togglish Checkboxen CodePen</a>, and his much longer write-up
<a href="http://adrianroselli.com/2019/03/under-engineered-toggles.html">Under Engineered toggles</a>.
</p>
</section> <!-- /.demo-details -->
</div>
</main>
</div> <!-- /.demo-wrap -->
<script src="../assets/js/switch-checkbox.js"></script>
<script>
// some other file.js
var selector = '[data-check-switch]';
var elList = document.querySelectorAll(selector);
var i;
for ( i = 0; i < elList.length; i++ ) {
var a11ySwitch = new A11YswitchCheck();
a11ySwitch.init( elList[i] );
};
</script>
<script>
var highlighterCSS = function () {
var head = document.head;
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '../assets/vendor/prism.css';
head.appendChild(link);
}
highlighterCSS();
</script>
<script src="../assets/vendor/prism.js"></script>
</body>
</html>