Progress Bar (Unbounded)

The unbounded progress bar is not tied to any progressive increments. It is basically a "busy" or "in progress" message. It will continue until it is cancelled by another event. If there is no such event, it will continue forever.

Note:

The unbounded progress bar is not keyboard-focusable, so if you want to hear it read by a screen reader, you will need to navigate to it via text navigation (down arrow key in JAWS and NVDA; Alt + right arrow in Narrator; Control + Option + Right arrow in VoiceOver)



Initial HTML Markup

<div id="progressbar-unbounded" class="deque-progressbar deque-progressbar-unbounded">
  <progress role="progressbar"
  aria-valuetext="In progress, please wait..."
  aria-label="An unbounded progress bar which will run like this forever.">
  </progress>
  <p>
    <button class="deque-button" id="start-progressbar">
      Start
    </button>
    <button class="deque-button" id="stop-progressbar">
      Stop
    </button>
  </p>
</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 @progressbar section:


	function createProgressBar(progressBar, _ref) {
	  var _ref$bounded = _ref.bounded,
	      bounded = _ref$bounded === undefined ? false : _ref$bounded;
	
	  if (bounded) {
	    var minValue = progressBar.getAttribute('aria-valuemin');
	    var maxValue = progressBar.getAttribute('aria-valuemax');
	    progressBar.setAttribute('value-now', minValue);
	    progressBar.setAttribute('max', maxValue);
	    progressBar.setValue = function (v) {
	      if (v < minValue) {
	        v = minValue;
	      }
	
	      if (v > maxValue) {
	        v = maxValue;
	      }
	
	      var percent = parseInt(v / maxValue * 100);
	
	      progressBar.innerText = percent + '%';
	      progressBar.setAttribute('aria-valuenow', v);
	      progressBar.setAttribute('value-now', v);
	      progressBar.setAttribute('value', v);
	    };
	    progressBar.setValue(minValue);
	  }
	  return progressBar;
	}
	

Required: Initialization JavaScript (with functionality specific to individual pattern instances):

var host = document.getElementById('progressbar-unbounded');
var progressBar = host.querySelector('progress');
progressBar.classList.add('deque-hidden');

var unboundedProgressBar = deque.createProgressBar(progressBar, {bounded: false});
unboundedProgressBar.id = 'unboundedProgressBar';
unboundedProgressBar.setAttribute(
  'aria-label',
  'An unbounded progress bar which will run like this forever.'
);

var startButton = host.querySelector('#start-progressbar');
startButton.addEventListener('click', function() {
  unboundedProgressBar.classList.add('deque-progressbar');
  unboundedProgressBar.classList.add('deque-progressbar-unbounded');
  unboundedProgressBar.classList.remove('deque-hidden');
  unboundedProgressBar.setAttribute('aria-busy', 'true');
});

var stopButton = host.querySelector('#stop-progressbar');
stopButton.addEventListener('click', function() {
  unboundedProgressBar.classList.remove('deque-progressbar');
  unboundedProgressBar.classList.remove('deque-progressbar-unbounded');
  unboundedProgressBar.classList.add('deque-hidden');
  unboundedProgressBar.setAttribute('aria-busy', 'false');
});

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-progressbar[role='progressbar'] {
  width: 100%;
  background: #ffffff;
  appearance: none;
  border: 1px solid #cccccc;
  min-width: 296px;
  height: 4px;
  display: block;
  margin-top: 12px;
}
.deque-progressbar[role='progressbar'][aria-valuenow='100'] {
  border: 1px solid #006cc1;
}
.deque-progressbar[role='progressbar']:indeterminate::-moz-progress-bar {
  background: rgba(0, 0, 0, 0);
}
.deque-progressbar[role='progressbar']::-webkit-progress-bar {
  background: rgba(0, 0, 0, 0);
}
.deque-progressbar[role='progressbar']::-webkit-progress-value {
  background: #006cc1;
}
.deque-progressbar[role='progressbar']::-moz-progress-bar {
  background: #006cc1;
}
.deque-progressbar[role='progressbar'] > [role='progressbar'] {
  display: block;
  position: relative;
  background: rgba(0, 0, 0, 0.2);
  min-width: 296px;
  width: 100%;
  height: 4px;
}
.deque-progressbar[role='progressbar'] > [role='progressbar'] > span {
  display: block;
  position: relative;
  height: 100%;
  background: #0078d7;
  color: #0078d7;
}
.deque-progressbar-unbounded[role='progressbar'] {
  appearance: none;
  color: rgba(0, 0, 0, 0);
  border: 0;
  min-width: 296px;
  height: 4px;
  animation: move 20s linear infinite;
  background: linear-gradient(to right, #006cc1 0%, rgba(255, 255, 255, 0) 50%, #006cc1 100%);
  display: block;
  margin-top: 12px;
}
@keyframes move {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -10000px 0;
  }
}
@-webkit-keyframes move {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -10000px 0;
  }
}
@-moz-keyframes move {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -10000px 0;
  }
}

Implementation Instructions

Implement the Progress Bar pattern when you want to provide either a bounded or unbounded progress bar that is accessible on your web page or application.

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

  • Wrap the HTML in <div> container with a unique ID and class="deque-progressbar deque-progressbar-unbounded", for styling purposes.
    • Create a <progress> container with role="progressbar", aria-valuetext="In progress, please wait...", and aria-label="An unbounded progress bar which will run like this forever.".
    • Add the buttons within a <p> container.
      • Create two buttons, the start button and the stop button, each within a <button> container with class="deque-button", for styling purposes, and a unique ID.

Step 3: Add JavaScript

  1. Use the unique ID of progressbar container to select the <div>.
  2. Select the <progress> container and pass it into deque.createProgressBar() along with a single key, bounded.
  3. If you want the progress bar to be unbounded, set the bounded key value to false. If bounded is false, the progress bar simply does nothing, but it can be visually animated to denote that something is in progress.
  4. Using their unique IDs, initialize the buttons. The example above hides the progress bar using class="deque-hidden" until the start button is selected. The stop button hides the pattern again.