Skip to content

Commit

Permalink
Add example of switch made from div element (pull #1892)
Browse files Browse the repository at this point in the history
Co-authored-by: Michiel Bijl <Michiel@Moiety.local>
Co-authored-by: Matt King <a11yThinker@gmail.com>
Co-authored-by: Michiel Bijl <michiel.bijl@crowdstrike.com>
  • Loading branch information
4 people committed Oct 4, 2021
1 parent a5c056f commit 594fe37
Show file tree
Hide file tree
Showing 6 changed files with 487 additions and 6 deletions.
9 changes: 3 additions & 6 deletions aria-practices.html
Expand Up @@ -2581,13 +2581,10 @@ <h3>Switch</h3>
<section class="notoc">
<h4>Examples</h4>
<ul>
<li>To be added.</li>
<!--
<li>
<a href="examples/switch/switch.html">Switch using <code>div</code> element Example</a>: Demonstrates switches used for turning on/off notifications.</li>
<li><a href="examples/switch/switch.html">Switch Example</a>: A switch based on a <code>div</code> element that turns a notification preference on and off.</li>
<!-- comment out examples not yet merged.
<li><a href="examples/switch/switch-button.html">Switch using <code>button</code> element Example</a>: Demonstrates switches used for turning on/off lights.</li>
<li><a href="examples/switch/switch-checkbox.html">Switch using <code>input[type=&quot;checkbox&quot;]</code> element Example</a>: Demonstrates switches used for turning on/off accessibility preferences.
</li>
<li><a href="examples/switch/switch-checkbox.html">Switch using <code>input[type=&quot;checkbox&quot;]</code> element Example</a>: Demonstrates switches used for turning on/off accessibility preferences.</li>
-->
</ul>
</section>
Expand Down
6 changes: 6 additions & 0 deletions examples/index.html
Expand Up @@ -359,6 +359,10 @@ <h2 id="examples_by_role_label">Examples by Role</h2>
</ul>
</td>
</tr>
<tr>
<td><code>switch</code></td>
<td><a href="switch/switch.html">Switch</a></td>
</tr>
<tr>
<td><code>tab</code></td>
<td>
Expand Down Expand Up @@ -481,6 +485,7 @@ <h2 id="examples_by_props_label">Examples By Properties and States</h2>
<li><a href="menubar/menubar-editor.html">Editor Menubar</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="radio/radio-activedescendant.html">Radio Group Using aria-activedescendant</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="radio/radio.html">Radio Group Using Roving tabindex</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="switch/switch.html">Switch</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="toolbar/toolbar.html">Toolbar</a></li>
</ul>
</td>
Expand Down Expand Up @@ -608,6 +613,7 @@ <h2 id="examples_by_props_label">Examples By Properties and States</h2>
<li><a href="slider/slider-seek.html">Media Seek Slider</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="slider/slider-temperature.html">Vertical Temperature Slider</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="spinbutton/datepicker-spinbuttons.html">Date Picker Spin Button</a></li>
<li><a href="switch/switch.html">Switch</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="toolbar/toolbar.html">Toolbar</a></li>
</ul>
</td>
Expand Down
73 changes: 73 additions & 0 deletions examples/switch/css/switch.css
@@ -0,0 +1,73 @@
[role="switch"] {
margin: 2px;
padding: 4px 4px 8px 8px;
border: 0 solid #005a9c;
border-radius: 5px;
width: 15em;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

[role="switch"] .label {
display: inline-block;
width: 8em;
}

[role="switch"] .switch {
position: relative;
display: inline-block;
top: 6px;
border: 2px solid black;
border-radius: 12px;
height: 20px;
width: 40px;
}

[role="switch"] .switch span {
position: absolute;
top: 2px;
left: 2px;
display: inline-block;
border: 2px solid black;
border-radius: 8px;
height: 12px;
width: 12px;
background: black;
}

[role="switch"][aria-checked="true"] .switch span {
left: 21px;
background: green;
border-color: green;
}

[role="switch"] .on {
display: none;
}

[role="switch"] .off {
display: inline;
}

[role="switch"][aria-checked="true"] .on {
display: inline;
}

[role="switch"][aria-checked="true"] .off {
display: none;
}

[role="switch"]:focus,
[role="switch"]:hover {
padding: 2px 2px 6px 6px;
border-width: 2px;
outline: none;
background-color: #def;
cursor: pointer;
}

[role="switch"]:focus span.switch {
background-color: white;
}
45 changes: 45 additions & 0 deletions examples/switch/js/switch.js
@@ -0,0 +1,45 @@
/*
* This content is licensed according to the W3C Software License at
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* File: switch.js
*
* Desc: Switch widget that implements ARIA Authoring Practices
*/

'use strict';

class Switch {
constructor(domNode) {
this.switchNode = domNode;
this.switchNode.addEventListener('click', () => this.toggleStatus());
this.switchNode.addEventListener('keydown', (event) =>
this.handleKeydown(event)
);
}

handleKeydown(event) {
// Only do something when space or return is pressed
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.toggleStatus();
}
}

// Switch state of a switch
toggleStatus() {
const currentState =
this.switchNode.getAttribute('aria-checked') === 'true';
const newState = String(!currentState);

this.switchNode.setAttribute('aria-checked', newState);
}
}

// Initialize switches
window.addEventListener('load', function () {
// Initialize the Switch component on all matching DOM nodes
Array.from(document.querySelectorAll('[role^=switch]')).forEach(
(element) => new Switch(element)
);
});
212 changes: 212 additions & 0 deletions examples/switch/switch.html
@@ -0,0 +1,212 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Switch Example | WAI-ARIA Authoring Practices 1.2</title>

<!-- Core js and css shared by all examples; do not modify when using this template. -->
<link rel="stylesheet" href="https://www.w3.org/StyleSheets/TR/2016/base.css">
<link rel="stylesheet" href="../css/core.css">
<script src="../js/examples.js"></script>
<script src="../js/highlight.pack.js"></script>
<script src="../js/app.js"></script>

<!-- js and css for this example. -->
<link href="css/switch.css" rel="stylesheet">
<script src="js/switch.js" type="text/javascript"></script>
</head>
<body>
<nav aria-label="Related Links" class="feedback">
<ul>
<li><a href="../../#browser_and_AT_support">Browser and Assistive Technology Support</a></li>
<li><a href="https://github.com/w3c/aria-practices/issues/new">Report Issue</a></li>
<li><a href="https://github.com/w3c/aria-practices/projects/2">Related Issues</a></li>
<li><a href="../../#switch">Design Pattern</a></li>
</ul>
</nav>
<main>
<h1>Switch Example</h1>
<p>
This example illustrates implementation of the <a href="../../#switch">switch design pattern</a> for a notification preferences control.
It uses a <code>div</code> element for the switch and CSS borders to provide graphical rendering of switch states.
</p>
<!-- Remove links to similar examples until they are merged.
<p>Similar examples include: </p>
<ul>
<li><a href="switch-button.html">Switch example using the <code>button</code> element.</a></li>
<li><a href="switch-checkbox.html">Switch example using the <code>input[type=checkbox]</code> element.</a>.</li>
</ul>
-->

<section>
<div class="example-header">
<h2 id="ex_label">Example</h2>
</div>
<div role="separator" id="ex_start_sep" aria-labelledby="ex_start_sep ex_label" aria-label="Start of"></div>
<div id="ex1">
<div
role="switch"
aria-checked="false"
tabindex="0">
<span class="label">Notifications</span>
<span class="switch">
<span></span>
</span>
<span class="on" aria-hidden="true">On</span>
<span class="off" aria-hidden="true">Off</span>
</div>
</div>
<div role="separator" id="ex_end_sep" aria-labelledby="ex_end_sep ex_label" aria-label="End of"></div>
</section>

<section>
<h2>Accessibility Features</h2>
<ul>
<li>
To make understanding the state of the switch easier for users with visual or cognitive disabilities, a text equivalent of the state (<q>on</q> or <q>off</q>) is displayed adjacent to the graphical state indicator.
CSS attribute selectors ensure the label displayed is synchronized with the value of the <code>input</code>.<br/>
<strong>NOTE:</strong> To prevent redundant announcement of the state by screen readers, the text indicators of state are hidden from assistive technologies with <code>aria-hidden</code>.
</li>
<li>Spacing, border widths and fill are important to ensure the graphical states are visible and discernible to people with visual impairments, including when browser or operating system high contrast settings are enabled:
<ul>
<li>To make the graphical representation of the state of a switch readily perceivable, two pixel borders are used for the switch state container and a solid color is used for the fill of the circles indicating the on and off states.</li>
<li>To ensure users can perceive the difference between the container and the circles used to indicate the state of the switch, there are two pixels of space between the container border and the circles.</li>
</ul>
</li>
<li>To enhance perceivability when operating the switches, visual keyboard focus and hover are styled using the CSS <code>:hover</code> and <code>:focus</code> pseudo-classes:
<ul>
<li>To make it easier to perceive focus and the relationship between a label and its associated switch, focus creates a border around both the switch and the label and also changes the background color.</li>
<li>To make it easier to perceive that clicking either the label or switch will activate the switch, the hover indicator is the same as the focus indicator.</li>
<li>To help people with visual impairments identify the switch as an interactive element, the cursor is changed to a pointer when hovering over the switch.</li>
<li>
Note: Because transparent borders are visible on some systems with operating system high contrast settings enabled, transparency cannot be used to create a visual difference between the element that is focused an other elements.
Instead of using transparency, the focused element has a thicker border and less padding.
When an element receives focus, its border changes from zero to two pixels and padding is reduced by two pixels.
When an element loses focus, its border changes from two pixels to two and padding is increased by two pixels.
</li>
</ul>
</li>
</ul>
</section>

<section>
<h2 id="kbd_label">Keyboard Support</h2>
<table aria-labelledby="kbd_label" class="def">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr data-test-id="key-tab">
<th><kbd>Tab</kbd></th>
<td>
<ul>
<li>Moves keyboard focus to the <code>switch</code>.</li>
</ul>
</td>
</tr>
<tr data-test-id="key-space">
<th><kbd>Space</kbd><br><kbd>Enter</kbd></th>
<td>
<ul>
<li>Toggle switch between on and off.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>

<section>
<h2 id="rps_label">Role, Property, State, and Tabindex Attributes</h2>
<table aria-labelledby="rps_label" class="data attributes">
<thead>
<tr>
<th scope="col">Role</th>
<th scope="col">Attribute</th>
<th scope="col">Element</th>
<th scope="col">Usage</th>
</tr>
</thead>
<tbody>
<tr data-test-id="switch-role">
<th scope="row"><code>switch</code></th>
<td></td>
<td><code>div</code></td>
<td>Identifies the <code>div</code> element as a <code>switch</code>.</td>
</tr>
<tr data-test-id="switch-tabindex">
<td></td>
<th scope="row"><code>tabindex="0"</code></th>
<td><code>div</code></td>
<td>Includes the switch in the page <kbd>Tab</kbd> sequence.</td>
</tr>
<tr data-test-id="switch-aria-checked">
<td></td>
<th scope="row"><code>aria-checked="false"</code></th>
<td><code>div</code></td>
<td>
<ul>
<li>Indicates the <code>switch</code> is off.</li>
<li>CSS attribute selectors (e.g. <code>[aria-checked="false"]</code>) are used to synchronize the visual states with the value of the <code>aria-checked</code> attribute.</li>
</ul>
</td>
</tr>
<tr data-test-id="switch-aria-checked">
<td></td>
<th scope="row"><code>aria-checked="true"</code></th>
<td><code>div</code></td>
<td>
<ul>
<li>Indicates the <code>switch</code> is on.</li>
<li>CSS attribute selectors (e.g. <code>[aria-checked="true"]</code>) are used to synchronize the visual states with the value of the <code>aria-checked</code> attribute.</li>
</ul>
</td>
</tr>
<tr data-test-id="aria-hidden">
<td></td>
<th scope="row"><code>aria-hidden="true"</code></th>
<td><code>span.on</code> and <code>span.off</code></td>
<td>
<ul>
<li>Removes the strings <q>on</q> and <q>off</q> that appear to the right of the switch from the accessible name of the switch.</li>
<li>These strings are included only for enhancing visual comprehension of the state; element states are not permitted in accessible names.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>

<section>
<h2>Javascript and CSS Source Code</h2>
<ul id="css_js_files">
<li>CSS: <a href="css/switch.css" type="tex/css">switch.css</a></li>
<li>Javascript: <a href="js/switch.js" type="text/javascript">switch.js</a></li>
</ul>
</section>

<section>
<h2 id="sc1_label">HTML Source Code</h2>
<div role="separator" id="sc1_start_sep" aria-labelledby="sc1_start_sep sc1_label" aria-label="Start of"></div>
<pre><code id="sc1"></code></pre>
<div role="separator" id="sc1_end_sep" aria-labelledby="sc1_end_sep sc1_label" aria-label="End of"></div>
<!--
The following script will show the reader the HTML source for the example that is in the div with ID 'ex1'.
It renders the HTML in the preceding pre element with ID 'sc1'.
If you change the ID of either the 'ex1' div or the 'sc1' pre, be sure to update the sourceCode.add function parameters.
-->
<script>
sourceCode.add('sc1', 'ex1', 'ex_label', 'css_js_files');
sourceCode.make();
</script>
</section>
</main>
<nav>
<!-- Update the pattern_ID parameter of this link to refer to the APG design pattern section related to this example. -->
<a href="../../#switch">Switch Design Pattern in WAI-ARIA Authoring Practices 1.2</a>
</nav>
</body>
</html>

0 comments on commit 594fe37

Please sign in to comment.