Range & Switches
Two more control types round out the Bootstrap 5 forms toolkit: .form-range, which
restyles a native <input type="range"> slider, and .form-switch,
which turns a plain checkbox into an iOS-style toggle. Both are still native HTML inputs under the
styling, which matters for accessibility. This lesson builds a TrailMap "max distance" slider and a
"parking available" switch.
Range Sliders: .form-range
Add .form-range to a native <input type="range">. It's still a
plain range input — min, max, step, and value
all work exactly as they do without Bootstrap; the class only changes how the track and thumb look.
<!-- TrailMap: max distance filter, 0-25 miles -->
<label for="maxDistance" class="form-label">Max Distance: 10 mi</label>
<input type="range" class="form-range" id="maxDistance" min="0" max="25" step="1" value="10">
Toggle Switches: .form-switch
A switch is a checkbox with two extra classes: .form-switch on the wrapping
.form-check div, and role="switch" is implied by that combination —
Bootstrap draws it as a pill-shaped track with a sliding circle instead of a square checkbox.
<!-- TrailMap: only show trails with parking -->
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="parkingOnly">
<label class="form-check-label" for="parkingOnly">Only show trails with parking</label>
</div>
Accessibility Considerations for Range and Switch Controls
Both controls stay accessible for the same reason: they're native inputs, so screen readers already know how to announce a range's current value and a switch's on/off state — Bootstrap's classes never take that away. Two things to get right yourself:
- Always pair a range or switch with a visible
<label>where the design allows it, connected with matchingfor/idattributes — exactly like any other form control. - When no visible label fits (a compact filter chip, for example), add
aria-labeldirectly on the input so assistive tech still has something to announce. - For a range slider whose value changes live, update the visible label text (as in the example above, "Max Distance: 10 mi") so sighted and screen-reader users both get the current value, not just the control's existence.
<!-- No visible label: use aria-label instead -->
<input type="range" class="form-range" aria-label="Maximum trail distance in miles" min="0" max="25">
Worked Example: A Trail Filter Panel with Both Controls
The slider and the switch together, as they'd sit inside TrailMap's trail-list filter sidebar:
<div class="panel p-3">
<div class="mb-3">
<label for="maxDistance" class="form-label">Max Distance: <span id="maxDistanceValue">10</span> mi</label>
<input type="range" class="form-range" id="maxDistance" min="0" max="25" value="10">
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="parkingOnly">
<label class="form-check-label" for="parkingOnly">Only show trails with parking</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="dogFriendlyOnly" checked>
<label class="form-check-label" for="dogFriendlyOnly">Dog friendly only</label>
</div>
</div>
Wiring the live "10" text up to the slider's input event is a one-line vanilla JS
addition — the same no-jQuery approach every interactive Bootstrap 5 component in this track uses.