Progress Bars
A Bootstrap 5 progress bar is a purely visual, purely-CSS way to show a value somewhere between empty and full — an upload's percent complete, a skill rating, or (as we'll build below) a TrailMap trail's difficulty meter. There's no bundled JavaScript at all: you set the width yourself, either inline or with Bootstrap 5.3's newer CSS custom property, and Bootstrap 5 supplies the striping, coloring, and animation on top of it.
1. The Basic .progress / .progress-bar Pair
The outer .progress element is the track (the full-width grey background); the inner
.progress-bar is the filled portion, sized with an inline width style.
<div class="progress">
<div class="progress-bar" role="progressbar"
style="width: 65%;"
aria-valuenow="65" aria-valuemin="0" aria-valuemax="100">
65%
</div>
</div>
2. Why the ARIA Attributes Matter
A progress bar is visual by nature — a sighted user reads the fill level at a glance. A screen
reader user cannot see that fill, so the three ARIA attributes are what actually communicate the
value: role="progressbar" identifies the element's purpose, and
aria-valuenow/aria-valuemin/aria-valuemax report the current
value and its range as numbers an assistive technology can announce out loud. Skipping them leaves
screen reader users with an announced element that has no reported value at all.
aria-valuenow should always be kept in sync with the visual width — if you change the inline width with JavaScript for a live upload progress bar, update aria-valuenow in that same line of code.3. Setting Width: Inline Style vs --bs-progress-width
The classic approach is an inline width style, shown above. Bootstrap 5.3 added a
second option: the --bs-progress-width CSS custom property, which .progress-bar
reads internally to size itself. Functionally the two are equivalent for a single bar — the custom
property is mainly useful when you want to set the width from a CSS rule (a stylesheet or a
<style> block) instead of an inline attribute, e.g. when the percentage comes from
a CSS variable set elsewhere on the page.
<!-- Classic: inline width -->
<div class="progress-bar" style="width: 40%;" role="progressbar"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
<!-- Bootstrap 5.3+: the --bs-progress-width custom property -->
<div class="progress-bar" style="--bs-progress-width: 40%;" role="progressbar"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
4. Striped and Animated Variants
Add .progress-bar-striped for a diagonal-stripe texture across the fill, and
.progress-bar-animated (used together with .progress-bar-striped) to make
those stripes slide continuously — a common way to signal "still in progress" for something like an
active file upload with an unknown finish time.
<!-- Striped -->
<div class="progress">
<div class="progress-bar progress-bar-striped" role="progressbar"
style="width: 75%;" aria-valuenow="75"
aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!-- Striped AND animated (moving stripes) -->
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
style="width: 45%;" aria-valuenow="45"
aria-valuemin="0" aria-valuemax="100"></div>
</div>
.bg-success, .bg-warning, or .bg-danger on the .progress-bar itself with striping/animation to signal both a state AND an in-progress action at once.5. Worked Example — TrailMap Difficulty Meter
A trail difficulty meter for Eagle Peak Trail, shown as a colored progress bar out of 5 difficulty points, plus a genuine upload-progress bar for the "Submit a Trail" form's photo upload step.
<!-- Difficulty meter: Eagle Peak Trail rated 4 out of 5 -->
<label class="form-label">Difficulty: Hard (4/5)</label>
<div class="progress" style="height: 10px;">
<div class="progress-bar bg-danger" role="progressbar"
style="width: 80%;"
aria-valuenow="4" aria-valuemin="0" aria-valuemax="5"></div>
</div>
<!-- Photo upload progress on the "Submit a Trail" form -->
<label class="form-label">Uploading trail-photo.jpg…</label>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-info"
role="progressbar" style="width: 58%;"
aria-valuenow="58" aria-valuemin="0" aria-valuemax="100">
58%
</div>
</div>
Note the difficulty meter uses aria-valuemax="5" instead of the usual 100 — the ARIA
attributes don't require a percentage scale, only that aria-valuenow sits between
aria-valuemin and aria-valuemax and that all three describe the same
unit consistently. The upload bar, being an actual in-progress action, adds the striped + animated
combo so it visually reads as "still working," not a static rating.