Accessible Styled Form Controls

Styled Progress Bar

Published:

Last updated:

Cross-browser styling for the HTML progress bar.

Pattern Demo

File Uploaded:

Pattern Details

Pattern Markup
<label for="tasks_comp2">
  Tasks Completed:
  <progress class="progress-bar"
    id="tasks_comp2"
    value="50" max="100"></progress>
</label>

<span id="file_status2">
  File Uploaded:
</span>
<progress class="progress-bar"
  aria-labelledby="file_status2"
  value="70" max="100"></progress>

<progress class="progress-bar"
  aria-label="Delivery Status"
  value="80" max="100"></progress>

Unlike many other form elements, a progress element is read-only, and the progress bar is modified by the completion of tasks by a user, or the application itself.

A task can refer to user flows, like a user's current progress in a sign up flow, or a task being performed by an application, or server. For example, using a progress bar to indicate the application updating after a form submission, or indicating the progress of a file upload within an application's UI.

For indicating the state of a finite gauge, such as available diskspace, a meter would be more semantically appropriate.

Styling a progress element

The progress element has support in all modern browsers, including Internet Explorer. The only catch to styling it is it requires the use of vendor prefixed selectors. Though, compared to the range element, there aren't that many to worry about.

Largely the prefixed selectors to be concerned with are the following:

::-webkit-progress-bar
Setting the background style for Webkit
::-ms-fill
Style for progress indicator in MicroSoft browsers
::-moz-progress-bar
Style for progress indicator in Firefox
::-webkit-progress-value
Style for progress indicator in webkit browsers

Additionally there are the ::-webkit-progress-inner-element and :indeterminate selectors. But they are not used for the styled progress elements shown here.

Affects on Screen Reader Announcements?

Even though the progress element has good accessibility support and feature implementation, not all screen readers have full support for the element, and styling a progress element can have detrimental affects in some instances.

Note: progress bars are not meant to be focusable elements, so the following tests were performed with the virtual cursor.

JAWS 2018, 2019 + Internet Explorer 11

A styled or unstyled progress element is not announced when using JAWS with Internet Explorer.

JAWS will read the visible text next to the progress bar, but will skip over the progress bar when navigating with the virtual cursor.

JAWS 2018, 2019 + Firefox 63, 65.0.2

A styled or unstyled progress element is announced the same way when using JAWS with Firefox.

The virtual cursor first stops on the visible label of the progress bar and announces the content. The virtual cursor then announces the progress bar and it's current value, ##% progress bar..

When retesting with JAWS 2019 and Firefox 65.0.2, a progress bar will not announce an accessible name provided by an aria-label.

JAWS 2018, 2019 + Chrome (latest)

Unstyled progress bars do not announce their accessible name, and styled progress bars convey no information at all.

NVDA 2018.4.1 + Firefox 65.0.2

When NVDA virtual cursor focuses a styled progress bar with an accessible name provided by a label, NVDA will announce:

First stop is the label element:
Clickable [Accessible name]
Second stop is the progress element:
progress bar ##%

When NVDA virtual cursor focuses a styled progress with an accessible name from aria-labelledby or aria-label, NVDA will announce:

[Accessible name (from aria labeling method)], progress bar ##%

NVDA 2018.2.1 + Chrome (latest at time of testing)

When NVDA virtual cursor focuses a styled or unstyled progress bar with an accessible name provided by a label, NVDA will announce:

[Accessible name (from visible label)], progress bar [Accessible name]

If an accessible name is provided by an aria-label or aria-labelledby then NVDA will ignore the current value and announce the accessible name in place of the value.

[Accessible name (if there's a visible label)], progress bar [Accessible name (from aria-label or aria-labelledby)]

The current value of the progress bar is not announced

NVDA 2018.4.1 + Chrome (72)

Similar to 2018.2.1, the primary difference is that now styled progress bars will announce as "half checked", regardless of what their actual value is.

VoiceOver + Safari 13.1.2 on macOS Catalina

An unstyled progress bar will receive its accessible name from a <label> element. If styled, the association between the label and the progress indicator will break, resulting in the progress bar having no accessible name.

If using aria-label or aria-labelledby to add an accessible name to a styled progress bar, it will be announced as a "group". A user will then need to navigate into the named "group" to hear the "progress indicator" role and value announcement.

Previous results

VoiceOver + Safari 11.1.1 on macOS High Sierra

VoiceOver + Safari 12.0.3 on macOS Mojave

Styling progress bars causes their announcement with VoiceOver to be altered and result in more VO focus stops for a user. A styled progress bar will no longer recognize its accessible name from a label. If using an aria-label or aria-labelledby with a progress bar, VoiceOver will announce the element as a group. A user will then need to enter the "group" to hear the accessible name and current value of the progress bar. An unstyled progress bar has no "group" announcements, regardless of how the accessible name is applied to the progress bar.

A styled progress bar, with a visible label, will be announced as:

Focus stop 1: [Accessible name (visible label)]
Focus stop 2: ## percent, progress indicator

A styled progress bar, with an aria-labelledby, will be announced as:

Focus stop 1: [Accessible name (visible label)]
Focus stop 2: [Accessible name], group
Focus stop 3: ## percent, progress indicator
Focus stop 4: end of [Accessible name], group

A styled progress bar, with an aria-label, will be announced as:

Focus stop 1: [Accessible name], group
Focus stop 2: [Accessible name], ## percent, progress indicator
Focus stop 3: end of [Accessible name], group

Note that VoiceOver + Chrome doesn't fair much better, as styled progress bars do not become groups, but are announced as "indeterminate progress indicator" regardless of their set value.

VoiceOver + Safari on iOS 11.4, 12.1.4, 14.4.2

Regardless of if they are styled or not, VoiceOver does not announce the role of a progress bar when it receives VO focus.

Unstyled progress bars will announce their accessible name and current value if they are swiped to with VoiceOver enabled. If using a <label> element to provide the progress bar its accessible name, VoiceOver will purposefully skip over the text label and instead directly focus the progress bar and announce its name and value as a single VO focus stop.

In contrast, styled progress bars will not behave as described above, even if they are properly associated with a <label. Rather VO will announce the label and the progress value as separate swipe stops. A <progress> can be forced to announce an accessible name, by giving it an aria-label, however this will oddly make the element unable to be discovered when searching by touch (i.e., dragging your finger around the screen to move VO focus).

A styled progress bar, with a visible label, will be announced as:

Focus stop 1: [Accessible name (visible text)]
Focus stop 2: ##%

A styled progress bar, with an aria-label, will be announced as (when swiped to):

[Accessible name], ##%

An unstyled progress bar with an associated <label> will be announced as:

[Accessible name], ##%

TalkBack (Android Accessibility Suite 6.2) + Android Chrome

TalkBack has no issues with announcing the accessible name of a progress bar, however regardless of a progress bar being styled or not, TalkBack paired with Chrome does not announce the current value of a progress bar.

Usage note:

Though the progress element is largely reporting the correct information to browsers, screen readers have quite a few kinks in how they announce the element to users.

At the time of testing, a styled progress bar won't be fully accessible in all screen reader and browser pairings. Instead it may be more appropriate to simply treat the progress bar as a visual decoration, hide it from screen readers, and provide visually hidden text as a means to consistently convey the information.