Progress Bar (Bounded)

Progress Bar (Bounded)

A bounded progress bar helps users understand how much time is remaining in a process. Both sighted and blind users should be informed of the intervals with the progress bar.



Turn on a screen reader to experience this example in action.

Initial HTML Markup

<div id="progressbar-bounded" class="deque-progressbar deque-progressbar-bounded">
  <progress role="progressbar"
  aria-valuemin="0"
  aria-valuemax="100"
  aria-label="A bounded progress bar from 0 to 100">
  </progress>
  <p>
    <button class="deque-button" id="start-progressbar">
      Start
    </button>
    <button class="deque-button" id="reset-progressbar">
      Reset
    </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-bounded');
var progressBar = host.querySelector('progress');
progressBar.classList.add('deque-hidden');

var boundedProgressBar = deque.createProgressBar(progressBar, {bounded: true});
boundedProgressBar.id = 'boundedProgressBar';

var alert = document.createElement('span');
alert.id = 'progress-live';
alert.setAttribute('aria-live', 'polite');
alert.classList.add('deque-visuallyhidden');
document.body.appendChild(alert);

var value = 1;

function startProgress() {
  return setInterval(function() {
    if (value > 100) {
      value = 100;
      clearInterval(interval);
      interval = null;
      boundedProgressBar.setValue(value);
      alert.innerHTML = boundedProgressBar.innerHTML;
      alert.innerHTML = 'Loading Complete';
      return boundedProgressBar.setAttribute('aria-busy', 'false');
    }
    boundedProgressBar.setValue(value);
    alert.innerHTML = boundedProgressBar.innerHTML;
    boundedProgressBar.setAttribute('aria-busy', 'true');
    value += 10;
  }, 1000);
}

var interval;

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

var resetButton = host.querySelector('#reset-progressbar');
resetButton.addEventListener('click', function() {
  value = 1;
  if (!interval) {
    interval = startProgress();
  }
});

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">

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", for styling purposes.
    • Create a <progress> container with role="progressbar", aria-valuemin="0", aria-valuemax="100", and aria-label="A bounded progress bar from 0 to 100".
    • Add the buttons within a <p> container.
      • Create two buttons, the start button and the reset 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 bounded, set the key value to true, then specify a setValue number.
  4. The progress bar has a function called 'setValue' which takes a number between 0 and 1 and sets the value to 100* that number (to represent percent).
  5. 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.
  6. 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 reset button activates the startProgress function.