Skip to content

Commit

Permalink
Add example of a radio group that implements a 5-star rating input (p…
Browse files Browse the repository at this point in the history
…ull #1870)

This example is intended to show an alternative way of implementing the rating input that is also implemented with a slider.
The slider allows for half stars whereas the radio is only five options.

Co-authored-by: Matt King <a11yThinker@gmail.com>
  • Loading branch information
jongund and mcking65 committed Nov 10, 2021
1 parent edddf9f commit fc85cba
Show file tree
Hide file tree
Showing 9 changed files with 849 additions and 0 deletions.
1 change: 1 addition & 0 deletions aria-practices.html
Expand Up @@ -2222,6 +2222,7 @@ <h4>Examples</h4>
<ul>
<li><a href="examples/radio/radio.html">Radio Group Example Using Roving tabindex</a></li>
<li><a href="examples/radio/radio-activedescendant.html">Radio Group Example Using aria-activedescendant</a></li>
<li><a href="examples/radio/radio-rating.html">Rating Radio Group Example</a>: Radio group that provides input for a five-star rating scale.</li>
</ul>
</section>

Expand Down
6 changes: 6 additions & 0 deletions examples/index.html
Expand Up @@ -263,6 +263,7 @@ <h2 id="examples_by_role_label">Examples by Role</h2>
<ul>
<li><a href="menu-button/menu-button-links.html">Navigation Menu Button</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="menubar/menubar-navigation.html">Navigation Menubar</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="radio/radio-rating.html">Rating Radio Group</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="slider/slider-multithumb.html">Horizontal Multi-Thumb Slider</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<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>
Expand Down Expand Up @@ -290,6 +291,7 @@ <h2 id="examples_by_role_label">Examples by Role</h2>
<td>
<ul>
<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-rating.html">Rating Radio Group</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="toolbar/toolbar.html">Toolbar</a></li>
</ul>
Expand All @@ -300,6 +302,7 @@ <h2 id="examples_by_role_label">Examples by Role</h2>
<td>
<ul>
<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-rating.html">Rating Radio Group</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="toolbar/toolbar.html">Toolbar</a></li>
</ul>
Expand Down Expand Up @@ -493,6 +496,7 @@ <h2 id="examples_by_props_label">Examples By Properties and States</h2>
<li><a href="checkbox/checkbox.html">Checkbox (Two State)</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<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-rating.html">Rating Radio Group</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-button.html">Switch Using HTML Button</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>
Expand Down Expand Up @@ -646,6 +650,7 @@ <h2 id="examples_by_props_label">Examples By Properties and States</h2>
<li><a href="link/link.html">Link</a></li>
<li><a href="menubar/menubar-editor.html">Editor Menubar</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="menubar/menubar-navigation.html">Navigation Menubar</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="radio/radio-rating.html">Rating Radio Group</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="slider/slider-multithumb.html">Horizontal Multi-Thumb 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="table/table.html">Table</a></li>
Expand Down Expand Up @@ -681,6 +686,7 @@ <h2 id="examples_by_props_label">Examples By Properties and States</h2>
<li><a href="menubar/menubar-navigation.html">Navigation Menubar</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="meter/meter.html">Meter</a></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-rating.html">Rating Radio Group</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="slider/slider-color-viewer.html">Color Viewer Slider</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
<li><a href="slider/slider-rating.html">Rating Slider</a> (<abbr title="High Contrast Support">HC</abbr>)</li>
Expand Down
76 changes: 76 additions & 0 deletions examples/radio/css/radio-rating.css
@@ -0,0 +1,76 @@
/* CSS Document */

.rating-radio label {
display: block;
}

.rating-radio svg g[role="radio"] {
color: #005a9c;
}

.rating-radio svg {
forced-color-adjust: auto;
touch-action: pan-y;
}

.rating-radio svg .focus-ring,
.rating-radio svg .focus-ring-none {
stroke-width: 0;
fill-opacity: 0;
}

.rating-radio svg .star {
stroke-width: 2px;
stroke: currentColor;
fill-opacity: 0;
}

.rating-radio svg .star-none {
stroke-width: 3px;
stroke: currentColor;
fill-opacity: 0;
}

.rating-radio[data-rating-value="5"] svg .star {
fill: currentColor;
fill-opacity: 1;
}

.rating-radio[data-rating-value="1"] svg .star-1 .star {
fill: currentColor;
fill-opacity: 1;
}

.rating-radio[data-rating-value="2"] svg .star-2 .star {
fill: currentColor;
fill-opacity: 1;
}

.rating-radio[data-rating-value="3"] svg .star-3 .star {
fill: currentColor;
fill-opacity: 1;
}

.rating-radio[data-rating-value="4"] svg .star-4 .star {
fill: currentColor;
fill-opacity: 1;
}

/* focus styling */

.rating-radio:focus {
outline: none;
}

.rating-radio svg g:focus {
outline: none;
}

.rating-radio svg g:focus .focus-ring {
stroke-width: 2px;
stroke: currentColor;
}

.rating-radio:hover {
cursor: pointer;
}
140 changes: 140 additions & 0 deletions examples/radio/js/radio-rating.js
@@ -0,0 +1,140 @@
/*
* This content is licensed according to the W3C Software License at
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* File: radio-rating.js
*
* Desc: Radio group widget that implements ARIA Authoring Practices
*/

'use strict';

class RatingRadioGroup {
constructor(groupNode) {
this.groupNode = groupNode;

this.radioButtons = [];

this.firstRadioButton = null;
this.lastRadioButton = null;

var rbs = this.groupNode.querySelectorAll('[role=radio]');

for (var i = 0; i < rbs.length; i++) {
var rb = rbs[i];

rb.tabIndex = -1;
rb.setAttribute('aria-checked', 'false');

rb.addEventListener('keydown', this.handleKeydown.bind(this));
rb.addEventListener('click', this.handleClick.bind(this));

this.radioButtons.push(rb);

if (!this.firstRadioButton) {
this.firstRadioButton = rb;
}
this.lastRadioButton = rb;
}

var value = groupNode.getAttribute('data-rating-value');
var index = parseInt(value);

if (value && index >= 0 && index < this.radioButtons.length) {
this.radioButtons[index].tabIndex = 0;
} else {
value = this.firstRadioButton.getAttribute('data-rating-value');
groupNode.getAttribute('data-rating-value', value);
this.firstRadioButton.tabIndex = 0;
}
}

setChecked(currentItem) {
this.groupNode.tabIndex = -1;
for (var i = 0; i < this.radioButtons.length; i++) {
var rb = this.radioButtons[i];
rb.setAttribute('aria-checked', 'false');
rb.tabIndex = -1;
}
this.currentValue = currentItem.getAttribute('data-rating');
this.groupNode.setAttribute('data-rating-value', this.currentValue);

currentItem.setAttribute('aria-checked', 'true');
currentItem.tabIndex = 0;
currentItem.focus();
}

setCheckedToPreviousItem(currentItem) {
var index;

if (currentItem === this.firstRadioButton) {
this.setChecked(this.lastRadioButton);
} else {
index = this.radioButtons.indexOf(currentItem);
this.setChecked(this.radioButtons[index - 1]);
}
}

setCheckedToNextItem(currentItem) {
var index;

if (currentItem === this.lastRadioButton) {
this.setChecked(this.firstRadioButton);
} else {
index = this.radioButtons.indexOf(currentItem);
this.setChecked(this.radioButtons[index + 1]);
}
}

/* EVENT HANDLERS */

handleKeydown(event) {
var tgt = event.currentTarget,
flag = false;

switch (event.key) {
case ' ':
case 'Enter':
this.setChecked(tgt);
flag = true;
break;

case 'Up':
case 'ArrowUp':
case 'Left':
case 'ArrowLeft':
this.setCheckedToPreviousItem(tgt);
flag = true;
break;

case 'Down':
case 'ArrowDown':
case 'Right':
case 'ArrowRight':
this.setCheckedToNextItem(tgt);
flag = true;
break;

default:
break;
}

if (flag) {
event.stopPropagation();
event.preventDefault();
}
}

handleClick(event) {
this.setChecked(event.currentTarget);
}
}

// Initialize radio button group

window.addEventListener('load', function () {
var radios = document.querySelectorAll('.rating-radio');
for (var i = 0; i < radios.length; i++) {
new RatingRadioGroup(radios[i]);
}
});
1 change: 1 addition & 0 deletions examples/radio/radio-activedescendant.html
Expand Up @@ -34,6 +34,7 @@ <h1>Radio Group Example Using aria-activedescendant</h1>
<p>Similar examples include: </p>
<ul>
<li><a href="radio.html">Radio Group Example Using Roving tabindex</a>: A radio button group that uses roving <code>tabindex</code> for managing keyboard focus.</li>
<li><a href="radio-rating.html">Rating Radio Group Example</a>: Radio group that provides input for a five-star rating scale.</li>
</ul>
<section>
<div class="example-header">
Expand Down

0 comments on commit fc85cba

Please sign in to comment.