Web Accessibility (a11y) & WCAG Compliance in Bootstrap
Web accessibility ensures applications are usable by everyone, including people who navigate using screen readers, keyboard-only input, high-contrast displays, or reduced motion settings. Bootstrap 5 is designed around W3C WAI-ARIA authoring practices, but building fully compliant WCAG 2.1 / 2.2 AA applications requires understanding semantic HTML, focus trapping, and screen-reader utilities.
In this lesson, you will master accessible ARIA roles, keyboard focus trapping, accessible form error wiring, contrast ratios, and the prefers-reduced-motion media query.
┌─────────────────────────────────────────────────────────────────────────────┐
│ Bootstrap Accessibility Architecture │
├───────────────────┬───────────────────────────┬─────────────────────────────┤
│ Semantic HTML │ ARIA & Screen Readers │ Focus & Motion │
├───────────────────┼───────────────────────────┼─────────────────────────────┤
│ <button> vs <div> │ aria-expanded="true/false"│ .focus-ring │
│ <nav aria-label> │ aria-controls="menuId" │ Modal focus trapping │
│ <main>, <header> │ .visually-hidden │ prefers-reduced-motion: │
│ <fieldset> │ role="alert" / live region│ reduce │
└───────────────────┴───────────────────────────┴─────────────────────────────┘
1. Screen Reader Utilities: .visually-hidden
When visual design omits visible text (e.g. icon-only buttons, badge counters), provide equivalent text for assistive technologies:
<!-- Accessible Icon Button -->
<button class="btn btn-outline-danger" type="button">
<i class="bi bi-trash" aria-hidden="true"></i>
<span class="visually-hidden">Delete project permanently</span>
</button>
<!-- Skip Navigation Link -->
<a class="visually-hidden-focusable btn btn-primary position-absolute top-0 start-0 m-2 z-3" href="#main-content">
Skip to main content
</a>
.visually-hidden: Hides content visually while preserving it for screen readers..visually-hidden-focusable: Becomes visible when focused via keyboard Tab.
2. Accessible Modals & Focus Trapping
When a Bootstrap modal opens:
- Focus is trapped inside the modal container so keyboard users cannot accidentally interact with background elements.
- The background is marked
aria-hidden="true". - When the modal closes, focus automatically restores to the trigger button that opened it.
<div class="modal fade" id="accessibleModal" tabindex="-1" aria-labelledby="modalTitle" aria-describedby="modalDesc" aria-modal="true" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title fs-5" id="modalTitle">Confirm Account Deletion</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close dialog"></button>
</div>
<div class="modal-body" id="modalDesc">
All your data will be permanently removed. This action cannot be reversed.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger">Confirm Delete</button>
</div>
</div>
</div>
</div>
3. Accessible Forms & Error Association
Screen readers cannot see color changes from red borders. Always associate error messages with inputs using aria-describedby and aria-invalid:
<div class="mb-3">
<label for="cardNumber" class="form-label">Credit Card Number</label>
<input
type="text"
class="form-control is-invalid"
id="cardNumber"
aria-describedby="cardError"
aria-invalid="true"
required
>
<div id="cardError" class="invalid-feedback">
Card number must be 16 digits without hyphens.
</div>
</div>
4. Reduced Motion (prefers-reduced-motion)
Bootstrap 5 automatically respects user OS accessibility settings for reduced motion. When a user enables "Reduce Motion" in their OS, Bootstrap's Sass mixins disable all CSS transitions, accordion slides, and carousel animations:
// Bootstrap internal reduced motion mixin
@mixin transition($transition...) {
@if length($transition) == 0 {
$transition: $transition-base;
}
@if $enable-transitions {
@if $enable-reduced-motion {
@media (prefers-reduced-motion: reduce) {
transition: none;
}
}
transition: $transition;
}
}
Summary & Key Takeaways
- Semantic HTML (
<button>,<nav>,<main>) is the foundation of accessible interfaces. .visually-hiddenand.visually-hidden-focusableprovide screen-reader context without disrupting visual layouts.- Bootstrap modals handle focus trapping and restore focus upon dismissal.
- Error states must use
aria-describedbyto guarantee assistive devices read error messages aloud. - Bootstrap disables animation transitions automatically under
prefers-reduced-motion: reduce.
Best Practices & Senior Guidance
- Never Replace
<button>with<div onclick>:<div>elements are not keyboard focusable and do not respond to Space or Enter without extensive manual JS scripting. - Verify Contrast Ratios with Light Text on Primary: Ensure text on buttons satisfies the WCAG 2.1 minimum contrast ratio of 4.5:1 for standard text.