Slider

A slider is a user interface pattern that allows users to select a value between a continuous scale (or at least the appearance of a continuous scale) between a minimum and maximum value. The user moves the slider horizontally or vertically to select a value. The design of this control is highly visual in the way it is portrayed on the screen, inviting the user to literally slide the control along the slider axis, but it works with the arrow keys on the keyboard as well. Touch device functionality is possible, but only when the HTML 5 <range> element is used as the basis for the pattern.



How many bedrooms are you looking for?

What's your maximum price point?

Initial HTML Markup

<div class="deque-slider">
  <p>How many bedrooms are you looking for?</p>
  <div>
    <input class="deque-slider-widget" type="range" min="1" max="4" value="1" step="1" aria-label="Bedroom Count" aria-valuetext="value: 1">
  </div>
  <label>value: </label>
</div>
<div class="deque-slider">
  <p>What's your maximum price point?</p>
  <div>
    <input class="deque-slider-widget" type="range" min="50000" max="1500000" value="50000" step="50000" aria-orientation="vertical" aria-label="Maximum House Value" aria-valuetext="value: $550000">
  </div>
  <label>value: $</label>
</div>

JavaScript

Required: The complete JavaScript file (for all patterns in the library): deque-patterns.min.js

Key parts of the JavaScript file

Note: The code below is functional only in the context of the complete JavaScript file.

In the @slider section:


	/*
	export default function createSlider(minValue = 0, maxValue = 100, initialValue = minValue, stepSize = 1, label = 'slider', orientation = 'horizontal', classes = [], labelFromValue = (v) => v) {
	  let output = document.createElement('input');
	  output.classList.add('deque');
	  output.classList.add('slider-widget');
	
	  if (isNaN(minValue) || isNaN(maxValue) || isNaN(initialValue) || isNaN(stepSize)) {
	    throw new Error('min, max, initial values must all be numbers. StepSize must be a number.');
	  }
	
	  if (minValue >= maxValue) {
	    throw new Error('minvalue must be less than maxvalue.');
	  }
	
	  if (initialValue < minValue || initialValue > maxValue) {
	    throw new Error('initial value not within bounds.');
	  }
	
	  if (orientation !== 'horizontal' && orientation !== 'vertical') {
	    throw new Error('orientation must be either "horizontal" or "vertical", or blank (defaults to horizontal)');
	  }
	
	  if (!Array.isArray(classes)) {
	    throw new Error('classes must be passed as an array.');
	  }
	
	  output.setAttribute('type', 'range');
	  output.setAttribute('min', minValue);
	  output.setAttribute('max', maxValue);
	  output.setAttribute('value', initialValue);
	  output.setAttribute('step', stepSize);
	
	  if (orientation === 'vertical') {
	    function shouldSetOrient() { // eslint-disable-line no-inner-declarations
	      // Internet Explorer 6-11
	      var isIE = false || !!document.documentMode; //@cc_on!@
	      // Edge 20+
	      var isEdge = !isIE && !!window.StyleMedia;
	      // Firefox 1.0+
	      var isFirefox = typeof InstallTrigger !== 'undefined';
	
	      return isIE || isEdge || isFirefox;
	    }
	    if(shouldSetOrient() === true){
	      output.setAttribute('orient', 'vertical');
	      output.setAttribute('aria-orientation', 'vertical');
	    } else {
	      output.setAttribute('aria-orientation', 'vertical');
	    }
	  }
	
	  classes.forEach(c => output.classList.add(c));
	
	  if (label) {
	    output.setAttribute('aria-label', label);
	  }
	
	  if (labelFromValue) {
	    output.addEventListener('change', () => {
	      output.setAttribute('aria-valuetext', 'value: ' + labelFromValue(output.value));
	    });
	  }
	
	  output.setAttribute('aria-valuetext', 'value: ' + labelFromValue(output.value));
	
	  return output;
	}
	*/
	
	function createSlider(slider, output, initialContent) {
	  var minValue = slider.getAttribute('min');
	  var initialValue = slider.getAttribute('value');
	  var maxValue = slider.getAttribute('max');
	  var stepSize = slider.getAttribute('step');
	  var orientation = slider.getAttribute('aria-orientation');
	
	  if (orientation === null) {
	    orientation = 'horizontal';
	  }
	
	  if (isNaN(minValue) || isNaN(maxValue) || isNaN(initialValue) || isNaN(stepSize)) {
	    throw new Error('min, max, initial values must all be numbers. StepSize must be a number.');
	  }
	
	  if (orientation !== 'horizontal' && orientation !== 'vertical') {
	    throw new Error('orientation must be either "horizontal" or "vertical", or blank (defaults to horizontal)');
	  }
	
	  if (orientation === 'vertical') {
	    var shouldSetOrient = function shouldSetOrient() {
	      // eslint-disable-line no-inner-declarations
	      // Internet Explorer 6-11
	      var isIE = /*@cc_on!@*/false || !!document.documentMode;
	      // Edge 20+
	      var isEdge = !isIE && !!window.StyleMedia;
	      // Firefox 1.0+
	      var isFirefox = typeof InstallTrigger !== 'undefined';
	
	      return isIE || isEdge || isFirefox;
	    };
	
	    if (shouldSetOrient() === true) {
	      slider.setAttribute('orient', 'vertical');
	    }
	  }
	
	  if (output) {
	    output.innerText = initialContent + ' ' + slider.value;
	    slider.addEventListener('change', function () {
	      slider.setAttribute('aria-valuetext', initialContent + slider.value);
	      output.innerText = initialContent + ' ' + slider.value;
	    });
	  }
	
	  slider.setAttribute('aria-valuetext', initialContent + ' ' + slider.value);
	}
	
	function activateAllSliders() {
	  var sliders = document.querySelectorAll('.deque-slider');
	  for (var i = 0; i < sliders.length; i++) {
	    var slider = sliders[i].querySelector('.deque-slider-widget');
	    var output = sliders[i].querySelector('label');
	    var initialContent = output.innerText;
	    createSlider(slider, output, initialContent);
	  }
	}
	
	activateAllSliders();
	

Note: No additional JavaScript initialization code is necessary for this pattern. All elements with class="deque-slider" will be initialized automatically by the external JavaScript file.

CSS

Required: The complete CSS file (for all patterns in the library): deque-patterns.min.css

Key styles within the CSS file (other styles may also be necessary):


.deque-slider .deque-slider-widget {
  -webkit-appearance: none;
}
.deque-slider .deque-slider-widget:focus {
  outline: none;
}
.deque-slider .deque-slider-widget:focus::-webkit-slider-thumb {
  outline: 1px dashed;
}
.deque-slider .deque-slider-widget:focus::-moz-range-thumb {
  outline: 1px dashed;
}
.deque-slider .deque-slider-widget:focus::-ms-thumb {
  outline: 1px dashed;
}
.deque-slider .deque-slider-widget::-webkit-slider-thumb {
  height: 24px;
  width: 8px;
  background: #0078d7;
  border: 1px solid transparent;
  padding: 0;
  border-radius: 4px;
  position: absolute;
  top: -10px;
  -webkit-appearance: none;
}
.deque-slider .deque-slider-widget::-moz-range-thumb {
  height: 24px;
  width: 8px;
  background: #0078d7;
  border: 1px solid transparent;
  padding: 0;
  border-radius: 4px;
  position: absolute;
  top: -10px;
  -moz-appearance: none;
}
.deque-slider .deque-slider-widget::-ms-thumb {
  height: 24px;
  width: 8px;
  background: #0078d7;
  border: 1px solid transparent;
  padding: 0;
  border-radius: 4px;
  position: absolute;
  top: -10px;
}
.deque-slider .deque-slider-widget::-webkit-slider-runnable-track {
  position: relative;
  height: 4px;
  background: rgba(0, 0, 0, 0.4);
  margin-top: 12px;
  border: 1px solid transparent;
}
.deque-slider .deque-slider-widget::-moz-range-track {
  position: relative;
  background: rgba(0, 0, 0, 0.4);
  margin-top: 12px;
  border: 1px solid transparent;
}
.deque-slider .deque-slider-widget::-ms-track {
  position: relative;
  height: 4px;
  background: rgba(0, 0, 0, 0.4);
  margin: 12px 0;
  border: 1px solid transparent;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical'] {
  -webkit-appearance: none;
  -webkit-transform: rotate(-90deg);
  -moz-transform: rotate(0deg);
  transform: rotate(-90deg);
  min-height: 130px;
  writing-mode: bt-lr;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical']::-webkit-slider-thumb {
  height: 24px;
  width: 8px;
  background: #0078d7;
  border: 1px solid transparent;
  padding: 0;
  border-radius: 4px;
  position: absolute;
  top: -10px;
  -webkit-appearance: none;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical']::-moz-range-thumb {
  height: 8px;
  width: 24px;
  background: #0078d7;
  border: 1px solid transparent;
  padding: 0;
  border-radius: 4px;
  position: absolute;
  top: -10px;
  -moz-appearance: none;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical']::-ms-thumb {
  height: 8px;
  width: 24px;
  background: #0078d7;
  border: 1px solid transparent;
  padding: 0;
  border-radius: 4px;
  position: absolute;
  top: -10px;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical']::-webkit-slider-runnable-track {
  -webkit-appearance: none;
  position: relative;
  width: 4px;
  background: rgba(0, 0, 0, 0.4);
  margin-top: 12px;
  border: 1px solid transparent;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical']::-moz-range-track {
  -moz-appearance: none;
  position: relative;
  background: rgba(0, 0, 0, 0.4);
  margin-top: 12px;
  border: 1px solid transparent;
}
.deque-slider .deque-slider-widget[aria-orientation='vertical']::-ms-track {
  position: relative;
  width: 4px;
  background: rgba(0, 0, 0, 0.4);
  height: 130px;
  margin: 0 12px;
  border: 1px solid transparent;
  color: transparent;
}
.deque-slider .deque-slider-widget[orient='vertical'] {
  transform: rotate(0deg);
}

Implementation Instructions

Implementing the Slider pattern can be done whenever you have a need for creating a slider that is accessible so that anyone is able use it to specify desired values while interacting with your application.

Prerequisites:

You must be prepared to supply basic information to be used in the pattern, such as a label, its values, orientation, etc.

Step 1: Add Dependencies

Add deque-patterns.min.css in the <head> of the document.

<link rel="stylesheet" type="text/css" href="deque-patterns.min.css"></li>

Add a script link to deque-patterns.min.js to the bottom of the page.

<script type="text/javascript" src="deque-patterns.min.js"></script>

Step 2: Add HTML

  • Create a <div> or <span> container for each slider, with class="deque-slider".
    • Include a <p> container with the inner text being the purpose of the slider (e.g. How many bedrooms are you looking for?).
    • Add a <div> or <span> container.
      • Create an <input> container with class="deque-slider-pattern" and with type="range". Also include the following attributes:
      • min
        The lowest value your slider can represent.
        max
        The highest value your slider can represent.
        value
        The initial value of your slider.
        step
        The value by an integer multiplication of which your slider's value can change.
        aria-label
        An accessible label for your slider.
        aria-orientation
        Your slider's orientation. Can be either 'horizontal' or 'vertical'. If this attribute is not included then the default is horizontal.
    • Create a <label> container. The inner text will be displayed below the slider and will change to correspond with the slider's value. What you originally write in the HTML will be tacked on the front of the value.