Code examples
Progress bar
There are many variations of progress bars and loading spinners, some of which may not need to be a true progress bar at all.
Support varies by screen reader. It’s recommended to add full aria attributes, even when using a native <progress>
element.
Use semantic HTML
- This semantic HTML contains all accessibility features by default.
- While not a requirement, it is focusable to increase discoverability.
<progress role="progressbar"
id="progress"
tabindex="0"
class="progress"
aria-label="File upload"
value="50"
aria-valuemin="0"
aria-valuenow="50"
aria-valuemax="100"
max="100">
Spinner loading takeover
- There are many variations of loaders / spinners.
- While a takeover spinner modal is present, other content on the page must be inert
Use semantic HTML
- This semantic HTML contains all accessibility features using a dialog.
- The
progress
element can be used to describe the state
- The
Ensure content is ready before being available
- If content is being loaded slowly behind the spinner inside an
aria-live
region, usearia-busy="true"
to keep it from being read until the update is complete
<!-- Use aria-busy if content doesn't all load at once -->
<div id="really-slow-app"
aria-live="polite"
aria-busy="false">
<button id="showModal">
Launch spinner
</button>
<dialog role="dialog"
class="takeover"
id="modal"
tabindex="-1"
aria-modal="true"
aria-labelledby="modal-title">
<section>
<div class="progress-spinner">
<progress role="progressbar"
id="modal-title"
tabindex="0"
aria-label="Loading">
</div>
</section>
</dialog>
</div>
Inline dynamic loading waiting example
This example dynamically injects progress updates that will be read by a screen reader
aria-busy="true"
has spotty support, but does indicate that the region is busyaria-describedby
is allows the current progress to be read when the button is focusedaria-disabled
reinforces that the save action is incompleterole="status
has an implicit aria-live=”polite” of polite andaria-atomic="true"
meaning the entire content of the status will be read on each update
<div
id="slow-app"
aria-live="polite">
<button
id="trigger-progressbar"
aria-describedby="progress-busy"
aria-disabled="false">
Save
</button>
<div class="progress-busy inert" role="status">
<span id="progress-busy">
</span>
</div>
</div>
Developer notes
Name
- Use
aria-label="Progress bar name"
when there is not a visible title.
Role
- Use
role="progressbar
Group
- If the progress bar is describing another region of the page, use
aria-describedby="progressbar-id"
to connect the two elements.
State
- The state will be read out to the screen reader user by default.
Focus
- Progress bar is not usually focusable.
Reference
- MagentaA11y applies WCAG Graphics Contrast Guidelines