diff --git a/examples/index.html b/examples/index.html
index 719a72a5e6..ffac167726 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -284,9 +284,10 @@
Examples by Role
slider
@@ -563,6 +564,7 @@ Examples By Properties and States
Navigation Menubar
Radio Group Using aria-activedescendant
Radio Group Using Roving tabindex
+ Horizontal Multi-Thumb Slider with Mobile Support
Date Picker Spin Button
Table
Tabs with Automatic Activation
@@ -740,9 +742,10 @@ Examples By Properties and States
@@ -752,9 +755,10 @@ Examples By Properties and States
@@ -765,9 +769,10 @@ Examples By Properties and States
@@ -777,8 +782,9 @@ Examples By Properties and States
aria-valuetext
diff --git a/examples/slider/css/multithumb-slider.css b/examples/slider/css/multithumb-slider.css
deleted file mode 100644
index a442e09d2f..0000000000
--- a/examples/slider/css/multithumb-slider.css
+++ /dev/null
@@ -1,48 +0,0 @@
-/* CSS Document */
-
-div.aria-widget-slider {
- clear: both;
- padding-top: 0.5em;
- padding-bottom: 1em;
-}
-
-div.rail-label {
- padding-right: 0.5em;
- text-align: right;
- float: left;
- width: 4em;
- position: relative;
- top: -0.5em;
-}
-
-div.rail-label.max {
- padding-left: 0.5em;
- text-align: left;
-}
-
-div.aria-widget-slider .rail {
- background-color: #eee;
- border: 1px solid #888;
- position: relative;
- height: 4px;
- float: left;
-}
-
-div.aria-widget-slider img[role="slider"] {
- position: absolute;
- padding: 0;
- margin: 0;
- top: -10px;
-}
-
-div.aria-widget-slider img[role="slider"].focus,
-div.aria-widget-slider img[role="slider"]:hover {
- outline-color: rgb(140, 203, 242);
- outline-style: solid;
- outline-width: 2px;
- outline-offset: 2px;
-}
-
-div.aria-widget-slider .rail.focus {
- background-color: #aaa;
-}
diff --git a/examples/slider/css/slider-multithumb.css b/examples/slider/css/slider-multithumb.css
new file mode 100644
index 0000000000..61d163392b
--- /dev/null
+++ b/examples/slider/css/slider-multithumb.css
@@ -0,0 +1,98 @@
+/* CSS Document */
+
+.slider-multithumb {
+ padding: 6px;
+ width: 350px;
+}
+
+.slider-multithumb.focus {
+ padding: 4px;
+ border: 2px solid #005a9c;
+ border-radius: 5px;
+}
+
+.slider-multithumb.mobile {
+ clear: both;
+ display: grid;
+ grid-template-columns: 100px 340px 100px;
+ grid-column-gap: 10px;
+ width: 550px;
+}
+
+.slider-multithumb.mobile .input-minimum,
+.slider-multithumb.mobile .input-maximum {
+ position: relative;
+ top: 32px;
+ height: 1.5em;
+}
+
+.slider-multithumb.mobile .input-minimum {
+ grid-column: 1;
+}
+
+.slider-multithumb.mobile .input-maximum {
+ grid-column: 3;
+}
+
+.slider-multithumb.mobile .slider-group {
+ grid-column: 2;
+}
+
+.slider-multithumb.mobile .input-minimum input,
+.slider-multithumb.mobile .input-maximum input {
+ width: 4em;
+}
+
+.slider-multithumb .slider-group .value {
+ font-size: 80%;
+ color: currentColor;
+ fill: currentColor;
+}
+
+.slider-multithumb .slider-group .rail {
+ stroke: currentColor;
+ stroke-width: 2px;
+ fill: #ccc;
+}
+
+.slider-multithumb .slider-group .thumb {
+ stroke: transparent;
+ stroke-width: 2px;
+ fill: currentColor;
+}
+
+.slider-multithumb .slider-group .focus {
+ stroke-width: 3px;
+ stroke: transparent;
+ fill: transparent;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+/* Focus and hover styling */
+
+.slider-multithumb.focus .slider-group {
+ color: #005a9c;
+}
+
+.slider-multithumb.focus .slider-group .rail {
+ stroke: currentColor;
+ fill: #adddff;
+}
+
+.slider-multithumb [role="slider"]:focus {
+ outline: none;
+}
+
+.slider-multithumb [role="slider"]:focus .focus {
+ stroke: currentColor;
+}
+
+.slider-multithumb [role="slider"]:focus .thumb {
+ stroke: currentColor;
+}
+
+.slider-multithumb [role="slider"]:focus .value {
+ color: currentColor;
+ font-weight: bold;
+}
diff --git a/examples/slider/js/multithumb-slider.js b/examples/slider/js/multithumb-slider.js
deleted file mode 100644
index 9f731049da..0000000000
--- a/examples/slider/js/multithumb-slider.js
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * This content is licensed according to the W3C Software License at
- * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- *
- * File: slider.js
- *
- * Desc: Slider widget that implements ARIA Authoring Practices
- */
-
-'use strict';
-
-// Create Slider that contains value, valuemin, valuemax, and valuenow
-var Slider = function (domNode) {
- this.domNode = domNode;
- this.railDomNode = domNode.parentNode;
-
- this.labelDomNode = false;
- this.minDomNode = false;
- this.maxDomNode = false;
-
- this.valueNow = 50;
-
- this.railMin = 0;
- this.railMax = 100;
- this.railWidth = 0;
- this.railBorderWidth = 1;
-
- this.thumbWidth = 20;
- this.thumbHeight = 24;
-
- this.keyCode = Object.freeze({
- left: 37,
- up: 38,
- right: 39,
- down: 40,
- pageUp: 33,
- pageDown: 34,
- end: 35,
- home: 36,
- });
-};
-
-// Initialize slider
-Slider.prototype.init = function () {
- if (this.domNode.previousElementSibling) {
- this.minDomNode = this.domNode.previousElementSibling;
- this.railMin = parseInt(this.minDomNode.getAttribute('aria-valuemin'));
- } else {
- this.railMin = parseInt(this.domNode.getAttribute('aria-valuemin'));
- }
-
- if (this.domNode.nextElementSibling) {
- this.maxDomNode = this.domNode.nextElementSibling;
- this.railMax = parseInt(this.maxDomNode.getAttribute('aria-valuemax'));
- } else {
- this.railMax = parseInt(this.domNode.getAttribute('aria-valuemax'));
- }
-
- this.valueNow = parseInt(this.domNode.getAttribute('aria-valuenow'));
-
- this.railWidth = parseInt(this.railDomNode.style.width.slice(0, -2));
-
- if (this.domNode.classList.contains('min')) {
- this.labelDomNode = this.domNode.parentElement.previousElementSibling;
- }
-
- if (this.domNode.classList.contains('max')) {
- this.labelDomNode = this.domNode.parentElement.nextElementSibling;
- }
-
- if (this.domNode.tabIndex != 0) {
- this.domNode.tabIndex = 0;
- }
-
- this.domNode.addEventListener('keydown', this.handleKeyDown.bind(this));
- this.domNode.addEventListener('mousedown', this.handleMouseDown.bind(this));
- this.domNode.addEventListener('focus', this.handleFocus.bind(this));
- this.domNode.addEventListener('blur', this.handleBlur.bind(this));
-
- this.moveSliderTo(this.valueNow);
-};
-
-Slider.prototype.moveSliderTo = function (value) {
- var valueMax = parseInt(this.domNode.getAttribute('aria-valuemax'));
- var valueMin = parseInt(this.domNode.getAttribute('aria-valuemin'));
-
- if (value > valueMax) {
- value = valueMax;
- }
-
- if (value < valueMin) {
- value = valueMin;
- }
-
- this.valueNow = value;
- this.dolValueNow = '$' + value;
-
- this.domNode.setAttribute('aria-valuenow', this.valueNow);
- this.domNode.setAttribute('aria-valuetext', this.dolValueNow);
-
- if (this.minDomNode) {
- this.minDomNode.setAttribute('aria-valuemax', this.valueNow);
- }
-
- if (this.maxDomNode) {
- this.maxDomNode.setAttribute('aria-valuemin', this.valueNow);
- }
-
- var pos = Math.round(
- ((this.valueNow - this.railMin) *
- (this.railWidth - 2 * (this.thumbWidth - this.railBorderWidth))) /
- (this.railMax - this.railMin)
- );
-
- if (this.minDomNode) {
- this.domNode.style.left =
- pos + this.thumbWidth - this.railBorderWidth + 'px';
- } else {
- this.domNode.style.left = pos - this.railBorderWidth + 'px';
- }
-
- if (this.labelDomNode) {
- this.labelDomNode.innerHTML = this.dolValueNow.toString();
- }
-};
-
-Slider.prototype.handleKeyDown = function (event) {
- var flag = false;
-
- switch (event.keyCode) {
- case this.keyCode.left:
- case this.keyCode.down:
- this.moveSliderTo(this.valueNow - 1);
- flag = true;
- break;
-
- case this.keyCode.right:
- case this.keyCode.up:
- this.moveSliderTo(this.valueNow + 1);
- flag = true;
- break;
-
- case this.keyCode.pageDown:
- this.moveSliderTo(this.valueNow - 10);
- flag = true;
- break;
-
- case this.keyCode.pageUp:
- this.moveSliderTo(this.valueNow + 10);
- flag = true;
- break;
-
- case this.keyCode.home:
- this.moveSliderTo(this.railMin);
- flag = true;
- break;
-
- case this.keyCode.end:
- this.moveSliderTo(this.railMax);
- flag = true;
- break;
-
- default:
- break;
- }
-
- if (flag) {
- event.preventDefault();
- event.stopPropagation();
- }
-};
-
-Slider.prototype.handleFocus = function (event) {
- this.domNode.classList.add('focus');
- this.railDomNode.classList.add('focus');
-};
-
-Slider.prototype.handleBlur = function (event) {
- this.domNode.classList.remove('focus');
- this.railDomNode.classList.remove('focus');
-};
-
-Slider.prototype.handleMouseDown = function (event) {
- var self = this;
-
- var handleMouseMove = function (event) {
- var diffX = event.pageX - self.railDomNode.offsetLeft;
- self.valueNow =
- self.railMin +
- parseInt(((self.railMax - self.railMin) * diffX) / self.railWidth);
- self.moveSliderTo(self.valueNow);
-
- event.preventDefault();
- event.stopPropagation();
- };
-
- var handleMouseUp = function (event) {
- document.removeEventListener('mousemove', handleMouseMove);
- document.removeEventListener('mouseup', handleMouseUp);
- };
-
- // bind a mousemove event handler to move pointer
- document.addEventListener('mousemove', handleMouseMove);
-
- // bind a mouseup event handler to stop tracking mouse movements
- document.addEventListener('mouseup', handleMouseUp);
-
- event.preventDefault();
- event.stopPropagation();
-
- // Set focus to the clicked handle
- this.domNode.focus();
-};
-
-// handleMouseMove has the same functionality as we need for handleMouseClick on the rail
-// Slider.prototype.handleClick = function (event) {
-
-// var diffX = event.pageX - this.railDomNode.offsetLeft;
-// this.valueNow = parseInt(((this.railMax - this.railMin) * diffX) / this.railWidth);
-// this.moveSliderTo(this.valueNow);
-
-// event.preventDefault();
-// event.stopPropagation();
-
-// };
-
-// Initialize Sliders on the page
-window.addEventListener('load', function () {
- var sliders = document.querySelectorAll('[role=slider]');
-
- for (var i = 0; i < sliders.length; i++) {
- var s = new Slider(sliders[i]);
- s.init();
- }
-});
diff --git a/examples/slider/js/slider-multithumb.js b/examples/slider/js/slider-multithumb.js
new file mode 100644
index 0000000000..9d84c568f0
--- /dev/null
+++ b/examples/slider/js/slider-multithumb.js
@@ -0,0 +1,394 @@
+/*
+ * This content is licensed according to the W3C Software License at
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * File: slider-multithumb.js
+ *
+ * Desc: A dual slider widget that implements ARIA Authoring Practices
+ */
+
+'use strict';
+class SliderMultithumb {
+ constructor(domNode) {
+ this.domNode = domNode;
+ this.svgNode = domNode.querySelector('svg');
+ this.railNode = domNode.querySelector('.rail');
+
+ this.minSliderNode = domNode.querySelector('[role=slider].minimum');
+ this.maxSliderNode = domNode.querySelector('[role=slider].maximum');
+
+ this.minSliderValueNode = this.minSliderNode.querySelector('.value');
+ this.maxSliderValueNode = this.maxSliderNode.querySelector('.value');
+
+ this.minSliderFocusNode = this.minSliderNode.querySelector('.focus');
+ this.maxSliderFocusNode = this.maxSliderNode.querySelector('.focus');
+
+ this.minSliderThumbNode = this.minSliderNode.querySelector('.thumb');
+ this.maxSliderThumbNode = this.maxSliderNode.querySelector('.thumb');
+
+ // The input elements are optional to support mobile devices,
+ // when a keyboard is not present
+ this.minInputNode = domNode.querySelector('.input-minimum input');
+ this.maxInputNode = domNode.querySelector('.input-maximum input');
+
+ if (this.minInputNode) {
+ this.minInputNode.addEventListener(
+ 'change',
+ this.onInputChange.bind(this)
+ );
+ this.minInputNode.addEventListener('blur', this.onInputChange.bind(this));
+ this.minInputNode.addEventListener('blur', this.onSliderBlur.bind(this));
+ this.minInputNode.addEventListener('focus', this.onSliderBlur.bind(this));
+ this.minInputNode.min = this.getValueMin(this.minSliderNode);
+ this.minInputNode.max = this.getValueMax(this.minSliderNode);
+ }
+
+ if (this.maxInputNode) {
+ this.maxInputNode.addEventListener(
+ 'change',
+ this.onInputChange.bind(this)
+ );
+ this.maxInputNode.addEventListener('blur', this.onInputChange.bind(this));
+ this.maxInputNode.addEventListener('blur', this.onSliderBlur.bind(this));
+ this.maxInputNode.addEventListener('focus', this.onSliderBlur.bind(this));
+ this.maxInputNode.min = this.getValueMin(this.maxSliderNode);
+ this.maxInputNode.max = this.getValueMax(this.maxSliderNode);
+ }
+
+ // Dimensions of the slider focus ring, thumb and rail
+
+ this.svgWidth = 360;
+ this.svgHeight = 80;
+
+ this.valueTop = 24;
+ this.valueHeight = this.minSliderValueNode.getBoundingClientRect().height;
+
+ this.railHeight = 6;
+ this.railWidth = 300;
+ this.railY = 42;
+ this.railX = 10;
+
+ this.thumbTop = 31;
+ this.thumbHeight = 28;
+ this.thumbWidth = 28;
+ this.thumb2Width = 2 * this.thumbWidth;
+ this.thumbMiddle = this.thumbTop + this.thumbHeight / 2;
+ this.thumbBottom = this.thumbTop + this.thumbHeight;
+
+ this.focusOffset = 8;
+ this.focusY = this.valueTop - this.valueHeight - this.focusOffset + 2;
+ this.focusWidth = this.thumbWidth + 2 * this.focusOffset;
+ this.focusHeight = this.thumbBottom - this.focusY + this.focusOffset + 2;
+
+ this.svgNode.setAttribute('width', this.svgWidth);
+ this.svgNode.setAttribute('height', this.svgHeight);
+
+ this.minSliderFocusNode.setAttribute('y', this.focusY);
+ this.maxSliderFocusNode.setAttribute('y', this.focusY);
+ this.minSliderFocusNode.setAttribute('width', this.focusWidth);
+ this.maxSliderFocusNode.setAttribute('width', this.focusWidth);
+ this.minSliderFocusNode.setAttribute('height', this.focusHeight);
+ this.maxSliderFocusNode.setAttribute('height', this.focusHeight);
+ this.minSliderFocusNode.setAttribute('rx', this.focusWidth / 2);
+ this.maxSliderFocusNode.setAttribute('rx', this.focusWidth / 2);
+
+ this.minSliderValueNode.setAttribute('y', this.valueTop);
+ this.maxSliderValueNode.setAttribute('y', this.valueTop);
+
+ this.railNode.setAttribute('y', this.railY);
+ this.railNode.setAttribute('x', this.railX);
+ this.railNode.setAttribute('height', this.railHeight);
+ this.railNode.setAttribute('width', this.railWidth + this.thumbWidth);
+ this.railNode.setAttribute('rx', this.railHeight / 2);
+
+ this.sliderMinValue = this.getValueMin(this.minSliderNode);
+ this.sliderMaxValue = this.getValueMax(this.maxSliderNode);
+
+ this.minSliderRight = 0;
+ this.maxSliderLeft = this.railWidth;
+
+ this.minSliderNode.addEventListener(
+ 'keydown',
+ this.onSliderKeydown.bind(this)
+ );
+ this.minSliderNode.addEventListener(
+ 'mousedown',
+ this.onSliderMousedown.bind(this)
+ );
+ this.minSliderNode.addEventListener('focus', this.onSliderFocus.bind(this));
+ this.minSliderNode.addEventListener('blur', this.onSliderBlur.bind(this));
+
+ this.maxSliderNode.addEventListener(
+ 'keydown',
+ this.onSliderKeydown.bind(this)
+ );
+ this.maxSliderNode.addEventListener(
+ 'mousedown',
+ this.onSliderMousedown.bind(this)
+ );
+ this.maxSliderNode.addEventListener('focus', this.onSliderFocus.bind(this));
+ this.maxSliderNode.addEventListener('blur', this.onSliderBlur.bind(this));
+
+ this.moveSliderTo(this.minSliderNode, this.getValue(this.minSliderNode));
+
+ this.moveSliderTo(this.maxSliderNode, this.getValue(this.maxSliderNode));
+ }
+
+ getValue(sliderNode) {
+ return parseInt(sliderNode.getAttribute('aria-valuenow'));
+ }
+
+ getValueMin(sliderNode) {
+ return parseInt(sliderNode.getAttribute('aria-valuemin'));
+ }
+
+ getValueMax(sliderNode) {
+ return parseInt(sliderNode.getAttribute('aria-valuemax'));
+ }
+
+ isMinSlider(sliderNode) {
+ return this.minSliderNode === sliderNode;
+ }
+
+ isMinInput(inputNode) {
+ return this.minInputNode === inputNode;
+ }
+
+ isInRange(sliderNode, value) {
+ let valueMin = this.getValueMin(sliderNode);
+ let valueMax = this.getValueMax(sliderNode);
+ return value <= valueMax && value >= valueMin;
+ }
+
+ isOutOfRange(value) {
+ let valueMin = this.getValueMin(this.minSliderNode);
+ let valueMax = this.getValueMax(this.maxSliderNode);
+ return value > valueMax || value < valueMin;
+ }
+
+ moveSliderTo(sliderNode, value) {
+ var valueMax,
+ valueMin,
+ pos,
+ x,
+ points = '',
+ width;
+
+ if (this.isMinSlider(sliderNode)) {
+ valueMin = this.getValueMin(this.minSliderNode);
+ valueMax = this.getValueMax(this.minSliderNode);
+ } else {
+ valueMin = this.getValueMin(this.maxSliderNode);
+ valueMax = this.getValueMax(this.maxSliderNode);
+ }
+
+ if (value > valueMax) {
+ value = valueMax;
+ }
+
+ if (value < valueMin) {
+ value = valueMin;
+ }
+
+ var dollarValue = '$' + value;
+ sliderNode.setAttribute('aria-valuenow', value);
+ sliderNode.setAttribute('aria-valuetext', dollarValue);
+
+ pos = this.railX;
+ pos += Math.round(
+ (value * (this.railWidth - this.thumbWidth)) /
+ (this.sliderMaxValue - this.sliderMinValue)
+ );
+
+ if (this.isMinSlider(sliderNode)) {
+ // update INPUT, label and ARIA attributes
+ this.minSliderValueNode.textContent = dollarValue;
+ this.maxSliderNode.setAttribute('aria-valuemin', value);
+
+ if (this.maxInputNode && this.minInputNode) {
+ this.maxInputNode.min = value;
+ this.minInputNode.value = value;
+ }
+
+ // move the SVG focus ring and thumb elements
+ x = pos - this.focusOffset - 1;
+ this.minSliderFocusNode.setAttribute('x', x);
+
+ points = `${pos},${this.thumbTop}`;
+ points += ` ${pos + this.thumbWidth},${this.thumbMiddle}`;
+ points += ` ${pos},${this.thumbBottom}`;
+ this.minSliderThumbNode.setAttribute('points', points);
+
+ // Position value
+ width = this.minSliderValueNode.getBoundingClientRect().width;
+ pos = pos + (this.thumbWidth - width) / 2;
+ if (pos + width > this.maxSliderLeft - 2) {
+ pos = this.maxSliderLeft - width - 2;
+ }
+ this.minSliderValueNode.setAttribute('x', pos);
+ this.minSliderRight = pos;
+ } else {
+ // move the SVG focus ring and thumb elements
+ x = pos + this.thumbWidth - this.focusOffset + 1;
+ this.maxSliderFocusNode.setAttribute('x', x);
+
+ points = `${pos + this.thumbWidth},${this.thumbMiddle}`;
+ points += ` ${pos + this.thumb2Width},${this.thumbTop}`;
+ points += ` ${pos + this.thumb2Width},${this.thumbBottom}`;
+ this.maxSliderThumbNode.setAttribute('points', points);
+
+ width = this.maxSliderValueNode.getBoundingClientRect().width;
+ pos = pos + this.thumbWidth + (this.thumbWidth - width) / 2;
+ if (pos - width < this.minSliderRight + 2) {
+ pos = this.minSliderRight + width + 2;
+ }
+ this.maxSliderValueNode.setAttribute('x', pos);
+ this.maxSliderLeft = pos;
+
+ // update INPUT, label and ARIA attributes
+ this.maxSliderValueNode.textContent = dollarValue;
+ this.minSliderNode.setAttribute('aria-valuemax', value);
+
+ if (this.maxInputNode && this.minInputNode) {
+ this.minInputNode.max = value;
+ this.maxInputNode.value = value;
+ }
+ }
+ }
+
+ onSliderKeydown(event) {
+ var flag = false;
+ var sliderNode = event.currentTarget;
+ var value = this.getValue(sliderNode);
+ var valueMin = this.getValueMin(sliderNode);
+ var valueMax = this.getValueMax(sliderNode);
+
+ switch (event.key) {
+ case 'ArrowLeft':
+ case 'ArrowDown':
+ this.moveSliderTo(sliderNode, value - 1);
+ flag = true;
+ break;
+
+ case 'ArrowRight':
+ case 'ArrowUp':
+ this.moveSliderTo(sliderNode, value + 1);
+ flag = true;
+ break;
+
+ case 'PageDown':
+ this.moveSliderTo(sliderNode, value - 10);
+ flag = true;
+ break;
+
+ case 'PageUp':
+ this.moveSliderTo(sliderNode, value + 10);
+ flag = true;
+ break;
+
+ case 'Home':
+ this.moveSliderTo(sliderNode, valueMin);
+ flag = true;
+ break;
+
+ case 'End':
+ this.moveSliderTo(sliderNode, valueMax);
+ flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (flag) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+
+ onSliderFocus() {
+ this.domNode.classList.add('focus');
+ }
+
+ onSliderBlur() {
+ this.domNode.classList.remove('focus');
+ }
+
+ onSliderMousedown(event) {
+ var onMousemove = function (e) {
+ var diffX = e.pageX - this.railNode.getBoundingClientRect().left;
+
+ if (isMinSlider) {
+ diffX -= this.thumbWidth / 2;
+ } else {
+ diffX -= (3 * this.thumbWidth) / 2;
+ }
+
+ var value = parseInt(
+ ((this.sliderMaxValue - this.sliderMinValue) * diffX) / this.railWidth
+ );
+
+ this.moveSliderTo(sliderNode, value);
+
+ e.preventDefault();
+ e.stopPropagation();
+ }.bind(this);
+
+ var onMouseup = function () {
+ document.removeEventListener('mousemove', onMousemove);
+ document.removeEventListener('mouseup', onMouseup);
+ };
+
+ var sliderNode = event.currentTarget;
+ var isMinSlider = this.isMinSlider(sliderNode);
+
+ // bind a mousemove event handler to move pointer
+ document.addEventListener('mousemove', onMousemove);
+
+ // bind a mouseup event handler to stop tracking mouse movements
+ document.addEventListener('mouseup', onMouseup);
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ // Set focus to the clicked handle
+ sliderNode.focus();
+ }
+
+ onInputChange(event) {
+ var tgt = event.currentTarget,
+ value = tgt.value,
+ isNumber = typeof parseInt(value) === 'number';
+
+ if (this.isMinInput(tgt)) {
+ if (value.length === 0) {
+ tgt.value = this.getValue(this.minSliderNode);
+ } else {
+ if (isNumber && this.isInRange(this.minSliderNode, value)) {
+ this.moveSliderTo(this.minSliderNode, value);
+ } else {
+ tgt.value = this.getValue(this.minSliderNode);
+ }
+ }
+ } else {
+ if (value.length === 0) {
+ tgt.value = this.getValue(this.maxSliderNode);
+ } else {
+ if (isNumber && this.isInRange(this.maxSliderNode, value)) {
+ this.moveSliderTo(this.maxSliderNode, value);
+ } else {
+ tgt.value = this.getValue(this.maxSliderNode);
+ }
+ }
+ }
+ }
+}
+
+// Initialize Multithumb Slider widgets on the page
+window.addEventListener('load', function () {
+ var slidersMultithumb = document.querySelectorAll('.slider-multithumb');
+
+ for (let i = 0; i < slidersMultithumb.length; i++) {
+ new SliderMultithumb(slidersMultithumb[i]);
+ }
+});
diff --git a/examples/slider/multithumb-slider.html b/examples/slider/multithumb-slider.html
deleted file mode 100644
index a40edc524d..0000000000
--- a/examples/slider/multithumb-slider.html
+++ /dev/null
@@ -1,277 +0,0 @@
-
-
-
-
- Horizontal Multi-Thumb Slider Example | WAI-ARIA Authoring Practices 1.2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Horizontal Multi-Thumb Slider Example
-
- The below example section includes a slider for setting a price range that demonstrates the
- multi-thumb slider design pattern.
- Users set a price range by moving the arrows (thumbs).
- Each slider has two thumbs: one for the minimum price and one for the maximum price.
- The price labels at the ends of the slider update as their corresponding thumbs are moved.
-
- Similar examples include:
-
-
-
-
-
-
Hotel Price Range
-
-
Flight Price Range
-
-
-
-
-
-
- Keyboard Support
-
-
-
- Key
- Function
-
-
-
-
- Right Arrow
- Increases slider value one step.
-
-
- Up Arrow
- Increases slider value one step.
-
-
- Left Arrow
- Decreases slider value one step.
-
-
- Down Arrow
- Decreases slider value one step.
-
-
- Page Up
- Increases slider value multiple steps. In this slider, jumps ten steps.
-
-
- Page Down
- Decreases slider value multiple steps. In this slider, jumps ten steps.
-
-
- Home
- Sets slider to its minimum value.
-
-
- End
- Sets slider to its maximum value.
-
-
-
-
-
-
- Role, Property, State, and Tabindex Attributes
-
-
-
- Role
- Attribute
- Element
- Usage
-
-
-
-
-
- slider
-
-
-
- img
-
-
-
- Identifies the img
element as a slider.
- Set on the movable thumb because it is the operable element that receives focus and represents the slider value.
-
-
-
-
-
-
- tabindex=0
-
-
- img
-
- Includes the slider thumb in the page tab sequence.
-
-
-
-
- aria-valuemax=NUMBER
-
-
- img
-
- Specifies the maximum value of the slider.
-
-
-
-
- aria-valuemin=NUMBER
-
-
- img
-
- Specifies the minimum value of the slider.
-
-
-
-
- aria-valuenow=NUMBER
-
-
- img
-
- Indicates the current value of the slider.
-
-
-
-
- aria-valuetext=DOLLAR AMOUNT
-
-
- img
-
- Indicates the current value of the slider in dollars using the $ character as a prefix.
-
-
-
-
- aria-label=text
-
-
- img
-
- A label identifying the purpose of the slider, e.g., Hotel Minimum Price .
-
-
-
-
-
-
- Javascript and CSS Source Code
-
-
-
-
- HTML Source Code
-
-
-
-
-
-
-
-
- Slider (Multi-Thumb) design pattern in WAI-ARIA Authoring Practices 1.2
-
-
-
diff --git a/examples/slider/slider-multithumb-mobile.html b/examples/slider/slider-multithumb-mobile.html
new file mode 100644
index 0000000000..68efa03923
--- /dev/null
+++ b/examples/slider/slider-multithumb-mobile.html
@@ -0,0 +1,354 @@
+
+
+
+
+ Horizontal Multi-Thumb Slider Example with Mobile Support | WAI-ARIA Authoring Practices 1.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Horizontal Multi-Thumb Slider Example with Mobile Support
+
+ The below example section includes a slider for setting a price range that demonstrates the
+ multi-thumb slider design pattern.
+ Users set a price range by moving the arrows (thumbs).
+ Each slider has two thumbs: one for the minimum price and one for the maximum price.
+ The price labels at the ends of the slider update as their corresponding thumbs are moved.
+
+ Similar examples include:
+
+
+
+
+
+
Hotel Price Range
+
+
Flight Price Range
+
+
+
+
+
+
+ Accessibility Features
+
+ A border is placed around the entire multi-thumbslider when one of the elements within the slider receives focus.
+ The placement of the slider value above the thumb supports users with low vision by allow them to more easily view the value of the slider as they move the thumb.
+ The SVG rect
element is used to encapsulate both the slider and slider value for the slider with keyboard focus.
+ The use SVG polygon
, rect
and text
elements enables the thumb, focus ring, value and rail of the slider to adapt to operating system high contrast colors.
+ The CSS currentColor
value for the fill
and stroke
properties of the thumb and slider is used to support the override colors in high contrast mode.
+ input[type=number]
for setting the low and higher values of the range support people using mobile devices to set the values.
+ input[type=number]
have tabindex=-1
so they are not part of the tab sequence of the page for keyboard users.
+
+
+
+
+ Keyboard Support
+
+
+
+ Key
+ Function
+
+
+
+
+ Right Arrow
+ Increases slider value one step.
+
+
+ Up Arrow
+ Increases slider value one step.
+
+
+ Left Arrow
+ Decreases slider value one step.
+
+
+ Down Arrow
+ Decreases slider value one step.
+
+
+ Page Up
+ Increases slider value multiple steps. In this slider, jumps ten steps.
+
+
+ Page Down
+ Decreases slider value multiple steps. In this slider, jumps ten steps.
+
+
+ Home
+ Sets slider to its minimum value.
+
+
+ End
+ Sets slider to its maximum value.
+
+
+
+
+
+ Role, Property, State, and Tabindex Attributes
+ Sliders
+
+
+
+ Role
+ Attribute
+ Element
+ Usage
+
+
+
+
+
+ slider
+
+
+
+ img
+
+
+
+ Identifies the img
element as a slider.
+ Set on the movable thumb because it is the operable element that receives focus and represents the slider value.
+
+
+
+
+
+
+ tabindex=0
+
+
+ img
+
+ Includes the slider thumb in the page tab sequence.
+
+
+
+
+ aria-valuemax=NUMBER
+
+
+ img
+
+ Specifies the maximum value of the slider.
+
+
+
+
+ aria-valuemin=NUMBER
+
+
+ img
+
+ Specifies the minimum value of the slider.
+
+
+
+
+ aria-valuenow=NUMBER
+
+
+ img
+
+ Indicates the current value of the slider.
+
+
+
+
+ aria-valuetext=DOLLAR AMOUNT
+
+
+ img
+
+ Indicates the current value of the slider in dollars using the $ character as a prefix.
+
+
+
+
+ aria-label=text
+
+
+ img
+
+ A label identifying the purpose of the slider, e.g., Hotel Minimum Price .
+
+
+
+
+ Input
+
+
+
+ Role
+ Attribute
+ Element
+ Usage
+
+
+
+
+
+
+ tabindex=-1
+
+
+ input[type=number]
+
+ When a keyboard is being used users can use keyboard commands to change the value of the slider widget and do not need to use the input
controls, so they are removed from the tab sequence of the page.
+
+
+
+
+
+ Javascript and CSS Source Code
+
+
+
+ HTML Source Code
+
+
+
+
+
+
+
+ Slider (Multi-Thumb) design pattern in WAI-ARIA Authoring Practices 1.2
+
+
+
diff --git a/examples/slider/slider-multithumb.html b/examples/slider/slider-multithumb.html
new file mode 100644
index 0000000000..8ce1e57ba0
--- /dev/null
+++ b/examples/slider/slider-multithumb.html
@@ -0,0 +1,287 @@
+
+
+
+
+ Horizontal Multi-Thumb Slider Example | WAI-ARIA Authoring Practices 1.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Horizontal Multi-Thumb Slider Example
+
+ The below example section includes a slider for setting a price range that demonstrates the
+ multi-thumb slider design pattern.
+ Users set a price range by moving the arrows (thumbs).
+ Each slider has two thumbs: one for the minimum price and one for the maximum price.
+ The price labels at the ends of the slider update as their corresponding thumbs are moved.
+
+ Similar examples include:
+
+
+
+
+
+
Hotel Price Range
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+
+
Flight Price Range
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+ Accessibility Features
+
+ A border is placed around the entire multi-thumbslider when one of the elements within the slider receives focus.
+ The placement of the slider value above the thumb supports users with low vision by allow them to more easily view the value of the slider as they move the thumb.
+ The SVG rect
element is used to encapsulate both the slider and slider value for the slider with keyboard focus.
+ The use SVG polygon
, rect
and text
elements enables the thumb, focus ring, value and rail of the slider to adapt to operating system high contrast colors.
+ The CSS currentColor
value for the fill
and stroke
properties of the thumb and slider is used to support the override colors in high contrast mode.
+
+
+
+
+ Keyboard Support
+
+
+
+ Key
+ Function
+
+
+
+
+ Right Arrow
+ Increases slider value one step.
+
+
+ Up Arrow
+ Increases slider value one step.
+
+
+ Left Arrow
+ Decreases slider value one step.
+
+
+ Down Arrow
+ Decreases slider value one step.
+
+
+ Page Up
+ Increases slider value multiple steps. In this slider, jumps ten steps.
+
+
+ Page Down
+ Decreases slider value multiple steps. In this slider, jumps ten steps.
+
+
+ Home
+ Sets slider to its minimum value.
+
+
+ End
+ Sets slider to its maximum value.
+
+
+
+
+
+ Role, Property, State, and Tabindex Attributes
+
+
+
+ Role
+ Attribute
+ Element
+ Usage
+
+
+
+
+
+ slider
+
+
+
+ img
+
+
+
+ Identifies the img
element as a slider.
+ Set on the movable thumb because it is the operable element that receives focus and represents the slider value.
+
+
+
+
+
+
+ tabindex=0
+
+
+ img
+
+ Includes the slider thumb in the page tab sequence.
+
+
+
+
+ aria-valuemax=NUMBER
+
+
+ img
+
+ Specifies the maximum value of the slider.
+
+
+
+
+ aria-valuemin=NUMBER
+
+
+ img
+
+ Specifies the minimum value of the slider.
+
+
+
+
+ aria-valuenow=NUMBER
+
+
+ img
+
+ Indicates the current value of the slider.
+
+
+
+
+ aria-valuetext=DOLLAR AMOUNT
+
+
+ img
+
+ Indicates the current value of the slider in dollars using the $ character as a prefix.
+
+
+
+
+ aria-label=text
+
+
+ img
+
+ A label identifying the purpose of the slider, e.g., Hotel Minimum Price .
+
+
+
+
+
+ Javascript and CSS Source Code
+
+
+
+ HTML Source Code
+
+
+
+
+
+
+
+ Slider (Multi-Thumb) design pattern in WAI-ARIA Authoring Practices 1.2
+
+
+
diff --git a/test/tests/slider_slider-multithumb-mobile.js b/test/tests/slider_slider-multithumb-mobile.js
new file mode 100644
index 0000000000..8872fd2edf
--- /dev/null
+++ b/test/tests/slider_slider-multithumb-mobile.js
@@ -0,0 +1,1163 @@
+const { ariaTest } = require('..');
+const { Key } = require('selenium-webdriver');
+const assertAttributeValues = require('../util/assertAttributeValues');
+const assertAriaLabelExists = require('../util/assertAriaLabelExists');
+const assertAriaRoles = require('../util/assertAriaRoles');
+
+const exampleFile = 'slider/slider-multithumb-mobile.html';
+
+const ex = {
+ inputSelector: '#ex1 input[type="number"]',
+ sliderSelector: '#ex1 [role="slider"]',
+ hotelSliderSelector: '#ex1 .slider-multithumb:nth-of-type(1) [role="slider"]',
+ flightSliderSelector:
+ '#ex1 .slider-multithumb:nth-of-type(2) [role="slider"]',
+ hotelMin: '0',
+ hotelMax: '400',
+ flightMin: '0',
+ flightMax: '1000',
+ hotelDefaultValues: ['100', '250'],
+ flightDefaultValues: ['100', '250'],
+ hotelLabelSelector:
+ '#ex1 .slider-multithumb:nth-of-type(1) [role=slider] .value',
+ flightLabelSelector:
+ '#ex1 .slider-multithumb:nth-of-type(2) [role=slider] .value',
+};
+
+const verifyAllValues = async function (
+ t,
+ value,
+ slider1,
+ attribute1,
+ slider2,
+ attribute2,
+ label,
+ message
+) {
+ t.is(
+ await slider1.getAttribute(attribute1),
+ value,
+ attribute1 + ' on first slider: ' + message
+ );
+
+ t.is(
+ await slider2.getAttribute(attribute2),
+ value,
+ attribute2 + ' on second slider: ' + message
+ );
+
+ t.is(await label.getText(), '$' + value, 'value in label after: ' + message);
+};
+
+// Attributes
+
+ariaTest(
+ '"tabindex" set to "-1" on input elements',
+ exampleFile,
+ 'input-tabindex',
+ async (t) => {
+ await assertAttributeValues(t, ex.inputSelector, 'tabindex', '-1');
+ }
+);
+
+ariaTest(
+ 'role="slider" on div element',
+ exampleFile,
+ 'slider-role',
+ async (t) => {
+ await assertAriaRoles(t, 'ex1', 'slider', '4', 'g');
+ }
+);
+
+ariaTest(
+ '"tabindex" set to "0" on sliders',
+ exampleFile,
+ 'tabindex',
+ async (t) => {
+ await assertAttributeValues(t, ex.sliderSelector, 'tabindex', '0');
+ }
+);
+
+ariaTest(
+ '"aria-valuemax" set on sliders',
+ exampleFile,
+ 'aria-valuemax',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+
+ t.is(
+ await hotelSliders[0].getAttribute('aria-valuemax'),
+ ex.hotelDefaultValues[1],
+ 'Value of "aria-valuemax" for first hotel slider on page load should be: ' +
+ ex.hotelDefaultValues[1]
+ );
+ t.is(
+ await hotelSliders[1].getAttribute('aria-valuemax'),
+ ex.hotelMax,
+ 'Value of "aria-valuemax" for second hotel slider on page load should be: ' +
+ ex.hotelMax
+ );
+ t.is(
+ await flightSliders[0].getAttribute('aria-valuemax'),
+ ex.flightDefaultValues[1],
+ 'Value of "aria-valuemax" for first flight slider on page load should be: ' +
+ ex.flightDefaultValues[1]
+ );
+
+ t.is(
+ await flightSliders[1].getAttribute('aria-valuemax'),
+ ex.flightMax,
+ 'Value of "aria-valuemax" for second flight slider on page load should be: ' +
+ ex.flightMax
+ );
+ }
+);
+
+ariaTest(
+ '"aria-valuemin" set to "0" on sliders',
+ exampleFile,
+ 'aria-valuemin',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+
+ t.is(
+ await hotelSliders[0].getAttribute('aria-valuemin'),
+ '0',
+ 'Value of "aria-valuemin" for first hotel slider on page load should be: "0"'
+ );
+ t.is(
+ await hotelSliders[1].getAttribute('aria-valuemin'),
+ ex.hotelDefaultValues[0],
+ 'Value of "aria-valuemin" for second hotel slider on page load should be: ' +
+ ex.hotelDefaultValues[0]
+ );
+ t.is(
+ await flightSliders[0].getAttribute('aria-valuemin'),
+ '0',
+ 'Value of "aria-valuemin" for first flight slider on page load should be: "0"'
+ );
+ t.is(
+ await flightSliders[1].getAttribute('aria-valuemin'),
+ ex.flightDefaultValues[0],
+ 'Value of "aria-valuemin" for second flight slider on page load should be: ' +
+ ex.flightDefaultValues[0]
+ );
+ }
+);
+
+ariaTest(
+ '"aria-valuenow" reflects slider value',
+ exampleFile,
+ 'aria-valuenow',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+
+ t.is(
+ await hotelSliders[0].getAttribute('aria-valuenow'),
+ ex.hotelDefaultValues[0],
+ 'Value of "aria-valuenow" for first hotel slider on page load should be: ' +
+ ex.hotelDefaultValues[0]
+ );
+ t.is(
+ await hotelSliders[1].getAttribute('aria-valuenow'),
+ ex.hotelDefaultValues[1],
+ 'Value of "aria-valuenow" for second hotel slider on page load should be: ' +
+ ex.hotelDefaultValues[1]
+ );
+ t.is(
+ await flightSliders[0].getAttribute('aria-valuenow'),
+ ex.flightDefaultValues[0],
+ 'Value of "aria-valuenow" for first flight slider on page load should be: ' +
+ ex.flightDefaultValues[0]
+ );
+ t.is(
+ await flightSliders[1].getAttribute('aria-valuenow'),
+ ex.flightDefaultValues[1],
+ 'Value of "aria-valuenow" for second flight slider on page load should be: ' +
+ ex.flightDefaultValues[1]
+ );
+ }
+);
+
+ariaTest(
+ '"aria-valuetext" reflects slider value',
+ exampleFile,
+ 'aria-valuetext',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+
+ t.is(
+ await hotelSliders[0].getAttribute('aria-valuetext'),
+ '$' + ex.hotelDefaultValues[0],
+ 'Value of "aria-valuetext" for first hotel slider on page load should be: $' +
+ ex.hotelDefaultValues[0]
+ );
+ t.is(
+ await hotelSliders[1].getAttribute('aria-valuetext'),
+ '$' + ex.hotelDefaultValues[1],
+ 'Value of "aria-valuetext" for second hotel slider on page load should be: $' +
+ ex.hotelDefaultValues[1]
+ );
+ t.is(
+ await flightSliders[0].getAttribute('aria-valuetext'),
+ '$' + ex.flightDefaultValues[0],
+ 'Value of "aria-valuetext" for first flight slider on page load should be: $' +
+ ex.flightDefaultValues[0]
+ );
+ t.is(
+ await flightSliders[1].getAttribute('aria-valuetext'),
+ '$' + ex.flightDefaultValues[1],
+ 'Value of "aria-valuetext" for second flight slider on page load should be: $' +
+ ex.flightDefaultValues[1]
+ );
+ }
+);
+
+ariaTest(
+ '"aria-label" set on sliders',
+ exampleFile,
+ 'aria-label',
+ async (t) => {
+ await assertAriaLabelExists(t, ex.sliderSelector);
+ }
+);
+
+// Keys
+
+ariaTest(
+ 'Right arrow increases slider value by 1',
+ exampleFile,
+ 'key-right-arrow',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to lower hotel slider
+ await hotelSliders[0].sendKeys(Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[0]) + 1).toString(),
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one ARROW RIGHT to lower hotel slider'
+ );
+
+ await hotelSliders[0].sendKeys(Key.END, Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ ex.hotelDefaultValues[1],
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after END then one ARROW RIGHT to lower hotel slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await hotelSliders[1].sendKeys(Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[1]) + 1).toString(),
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one ARROW RIGHT to lower hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.END, Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMax,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after END then one ARROW RIGHT to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(
+ t,
+ ex.flightLabelSelector
+ );
+
+ // Send 1 key to lower flight slider
+ await flightSliders[0].sendKeys(Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[0]) + 1).toString(),
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one ARROW RIGHT to lower flight slider'
+ );
+
+ await flightSliders[0].sendKeys(Key.END, Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ ex.flightDefaultValues[1],
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after END then one ARROW RIGHT to lower flight slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await flightSliders[1].sendKeys(Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[1]) + 1).toString(),
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one ARROW RIGHT to lower flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.END, Key.ARROW_RIGHT);
+
+ await verifyAllValues(
+ t,
+ ex.flightMax,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after END then one ARROW RIGHT to upper flight slider'
+ );
+ }
+);
+
+ariaTest(
+ 'Up arrow increases slider value by 1',
+ exampleFile,
+ 'key-up-arrow',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to lower hotel slider
+ await hotelSliders[0].sendKeys(Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[0]) + 1).toString(),
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one ARROW UP to lower hotel slider'
+ );
+
+ await hotelSliders[0].sendKeys(Key.END, Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ ex.hotelDefaultValues[1],
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after END then one ARROW UP to lower hotel slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await hotelSliders[1].sendKeys(Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[1]) + 1).toString(),
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one ARROW UP to lower hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.END, Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMax,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after END then one ARROW UP to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(
+ t,
+ ex.flightLabelSelector
+ );
+
+ // Send 1 key to lower flight slider
+ await flightSliders[0].sendKeys(Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[0]) + 1).toString(),
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one ARROW UP to lower flight slider'
+ );
+
+ await flightSliders[0].sendKeys(Key.END, Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ ex.flightDefaultValues[1],
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after END then one ARROW UP to lower flight slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await flightSliders[1].sendKeys(Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[1]) + 1).toString(),
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one ARROW UP to lower flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.END, Key.ARROW_UP);
+
+ await verifyAllValues(
+ t,
+ ex.flightMax,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after END then one ARROW UP to upper flight slider'
+ );
+ }
+);
+
+ariaTest(
+ 'Page up increases slider value by 10',
+ exampleFile,
+ 'key-page-up',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to lower hotel slider
+ await hotelSliders[0].sendKeys(Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[0]) + 10).toString(),
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one PAGE UP to lower hotel slider'
+ );
+
+ await hotelSliders[0].sendKeys(Key.END, Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ ex.hotelDefaultValues[1],
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after END then one PAGE UP to lower hotel slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await hotelSliders[1].sendKeys(Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[1]) + 10).toString(),
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one PAGE UP to upper hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.END, Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMax,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after END then one PAGE UP to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(
+ t,
+ ex.flightLabelSelector
+ );
+
+ // Send 1 key to lower flight slider
+ await flightSliders[0].sendKeys(Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[0]) + 10).toString(),
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one PAGE UP to lower flight slider'
+ );
+
+ await flightSliders[0].sendKeys(Key.END, Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ ex.flightDefaultValues[1],
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after END then one PAGE UP to lower flight slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await flightSliders[1].sendKeys(Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[1]) + 10).toString(),
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one PAGE UP to upper flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.END, Key.PAGE_UP);
+
+ await verifyAllValues(
+ t,
+ ex.flightMax,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after END then one PAGE UP to upper flight slider'
+ );
+ }
+);
+
+ariaTest(
+ 'left arrow decreases slider value by 1',
+ exampleFile,
+ 'key-left-arrow',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to lower hotel slider
+ await hotelSliders[0].sendKeys(Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[0]) - 1).toString(),
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one ARROW LEFT to lower hotel slider'
+ );
+
+ await hotelSliders[0].sendKeys(Key.HOME, Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after HOME then one ARROW LEFT to lower hotel slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await hotelSliders[1].sendKeys(Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[1]) - 1).toString(),
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one ARROW LEFT to upper hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.HOME, Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after HOME then one ARROW LEFT to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(
+ t,
+ ex.flightLabelSelector
+ );
+
+ // Send 1 key to lower flight slider
+ await flightSliders[0].sendKeys(Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[0]) - 1).toString(),
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one ARROW LEFT to lower flight slider'
+ );
+
+ await flightSliders[0].sendKeys(Key.HOME, Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after HOME then one ARROW LEFT to lower flight slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await flightSliders[1].sendKeys(Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[1]) - 1).toString(),
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one ARROW LEFT to upper flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.HOME, Key.ARROW_LEFT);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after HOME then one ARROW LEFT to upper flight slider'
+ );
+ }
+);
+
+ariaTest(
+ 'down arrow decreases slider value by 1',
+ exampleFile,
+ 'key-down-arrow',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to lower hotel slider
+ await hotelSliders[0].sendKeys(Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[0]) - 1).toString(),
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one ARROW DOWN to lower hotel slider'
+ );
+
+ await hotelSliders[0].sendKeys(Key.HOME, Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after HOME then one ARROW DOWN to lower hotel slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await hotelSliders[1].sendKeys(Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[1]) - 1).toString(),
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one ARROW DOWN to upper hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.HOME, Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after HOME then one ARROW DOWN to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(
+ t,
+ ex.flightLabelSelector
+ );
+
+ // Send 1 key to lower flight slider
+ await flightSliders[0].sendKeys(Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[0]) - 1).toString(),
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one ARROW DOWN to lower flight slider'
+ );
+
+ await flightSliders[0].sendKeys(Key.HOME, Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after HOME then one ARROW DOWN to lower flight slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await flightSliders[1].sendKeys(Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[1]) - 1).toString(),
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one ARROW DOWN to upper flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.HOME, Key.ARROW_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after HOME then one ARROW DOWN to upper flight slider'
+ );
+ }
+);
+
+ariaTest(
+ 'page down decreases slider value by 10',
+ exampleFile,
+ 'key-page-down',
+ async (t) => {
+ const hotelSliders = await t.context.queryElements(
+ t,
+ ex.hotelSliderSelector
+ );
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to lower hotel slider
+ await hotelSliders[0].sendKeys(Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[0]) - 10).toString(),
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one PAGE DOWN to lower hotel slider'
+ );
+
+ await hotelSliders[0].sendKeys(Key.HOME, Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after HOME then one PAGE DOWN to lower hotel slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await hotelSliders[1].sendKeys(Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.hotelDefaultValues[1]) - 10).toString(),
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one PAGE DOWN to upper hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.HOME, Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after HOME then one PAGE DOWN to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(
+ t,
+ ex.flightLabelSelector
+ );
+
+ // Send 1 key to lower flight slider
+ await flightSliders[0].sendKeys(Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[0]) - 10).toString(),
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one PAGE DOWN to lower flight slider'
+ );
+
+ await flightSliders[0].sendKeys(Key.HOME, Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after HOME then one PAGE DOWN to lower flight slider'
+ );
+
+ // Send 1 key to lower upper slider
+ await flightSliders[1].sendKeys(Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ (parseInt(ex.flightDefaultValues[1]) - 10).toString(),
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one PAGE DOWN to lower flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.HOME, Key.PAGE_DOWN);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after HOME then one PAGE DOWN to upper flight slider'
+ );
+ }
+);
+
+ariaTest('home sends value to minimum', exampleFile, 'key-home', async (t) => {
+ const hotelSliders = await t.context.queryElements(t, ex.hotelSliderSelector);
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ // Send 1 key to upper hotel slider
+ await hotelSliders[1].sendKeys(Key.HOME);
+
+ await verifyAllValues(
+ t,
+ ex.hotelDefaultValues[0],
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one HOME to upper hotel slider'
+ );
+
+ // Send 1 key to upper hotel slider
+ await hotelSliders[0].sendKeys(Key.HOME);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMin,
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one HOME to lower hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(t, ex.flightLabelSelector);
+
+ // Send 1 key to upper flight slider
+ await flightSliders[1].sendKeys(Key.HOME);
+
+ await verifyAllValues(
+ t,
+ ex.flightDefaultValues[0],
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one HOME to upper flight slider'
+ );
+
+ // Send 1 key to upper flight slider
+ await flightSliders[0].sendKeys(Key.HOME);
+
+ await verifyAllValues(
+ t,
+ ex.flightMin,
+ flightSliders[0],
+ 'aria-valuenow',
+ flightSliders[1],
+ 'aria-valuemin',
+ flightLabels[0],
+ 'after one HOME to lower flight slider'
+ );
+});
+
+ariaTest('end sends value to minimum', exampleFile, 'key-end', async (t) => {
+ const hotelSliders = await t.context.queryElements(t, ex.hotelSliderSelector);
+ const hotelLabels = await t.context.queryElements(t, ex.hotelLabelSelector);
+
+ await hotelSliders[0].sendKeys(Key.END);
+
+ await verifyAllValues(
+ t,
+ ex.hotelDefaultValues[1],
+ hotelSliders[0],
+ 'aria-valuenow',
+ hotelSliders[1],
+ 'aria-valuemin',
+ hotelLabels[0],
+ 'after one END to lower hotel slider'
+ );
+
+ await hotelSliders[1].sendKeys(Key.END);
+
+ await verifyAllValues(
+ t,
+ ex.hotelMax,
+ hotelSliders[0],
+ 'aria-valuemax',
+ hotelSliders[1],
+ 'aria-valuenow',
+ hotelLabels[1],
+ 'after one END to upper hotel slider'
+ );
+
+ const flightSliders = await t.context.queryElements(
+ t,
+ ex.flightSliderSelector
+ );
+ const flightLabels = await t.context.queryElements(t, ex.flightLabelSelector);
+
+ await flightSliders[0].sendKeys(Key.END);
+
+ await verifyAllValues(
+ t,
+ ex.flightDefaultValues[1],
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[0],
+ 'after one END to lower flight slider'
+ );
+
+ await flightSliders[1].sendKeys(Key.END);
+
+ await verifyAllValues(
+ t,
+ ex.flightMax,
+ flightSliders[0],
+ 'aria-valuemax',
+ flightSliders[1],
+ 'aria-valuenow',
+ flightLabels[1],
+ 'after one END to upper flight slider'
+ );
+});
diff --git a/test/tests/slider_multithumb.js b/test/tests/slider_slider-multithumb.js
similarity index 98%
rename from test/tests/slider_multithumb.js
rename to test/tests/slider_slider-multithumb.js
index 46e6f47827..abd8afbe5a 100644
--- a/test/tests/slider_multithumb.js
+++ b/test/tests/slider_slider-multithumb.js
@@ -4,22 +4,23 @@ const assertAttributeValues = require('../util/assertAttributeValues');
const assertAriaLabelExists = require('../util/assertAriaLabelExists');
const assertAriaRoles = require('../util/assertAriaRoles');
-const exampleFile = 'slider/multithumb-slider.html';
+const exampleFile = 'slider/slider-multithumb.html';
const ex = {
sliderSelector: '#ex1 [role="slider"]',
- hotelSliderSelector:
- '#ex1 div.aria-widget-slider:nth-of-type(1) [role="slider"]',
+ hotelSliderSelector: '#ex1 .slider-multithumb:nth-of-type(1) [role="slider"]',
flightSliderSelector:
- '#ex1 div.aria-widget-slider:nth-of-type(2) [role="slider"]',
+ '#ex1 .slider-multithumb:nth-of-type(2) [role="slider"]',
hotelMin: '0',
hotelMax: '400',
flightMin: '0',
flightMax: '1000',
hotelDefaultValues: ['100', '250'],
flightDefaultValues: ['100', '250'],
- hotelLabelSelector: '#ex1 div.aria-widget-slider:nth-of-type(1) .rail-label',
- flightLabelSelector: '#ex1 div.aria-widget-slider:nth-of-type(2) .rail-label',
+ hotelLabelSelector:
+ '#ex1 .slider-multithumb:nth-of-type(1) [role=slider] .value',
+ flightLabelSelector:
+ '#ex1 .slider-multithumb:nth-of-type(2) [role=slider] .value',
};
const verifyAllValues = async function (
@@ -54,7 +55,7 @@ ariaTest(
exampleFile,
'slider-role',
async (t) => {
- await assertAriaRoles(t, 'ex1', 'slider', '4', 'img');
+ await assertAriaRoles(t, 'ex1', 'slider', '4', 'g');
}
);