Quick answer: A Bootstrap 5 carousel is a div.carousel.slide holding a carousel-inner of carousel-item slides — exactly one of which carries the active class. Add carousel-indicators, carousel-control-prev and carousel-control-next for dots and arrows, and the bundle JavaScript handles sliding, autoplay and swipe. The usual failures are a missing bundle script, no active class on the first slide, and slides of different heights that make the page jump.
Part of our Bootstrap series; add the framework first with getting started with Bootstrap 5 if you have not already.
The complete carousel
Three slides with dots and arrows, autoplaying every five seconds. Every piece here is optional except the wrapper, the inner and the items.
<div id="heroCarousel" class="carousel slide" data-bs-ride="carousel">
<!-- dots -->
<div class="carousel-indicators">
<button type="button" data-bs-target="#heroCarousel" data-bs-slide-to="0"
class="active" aria-current="true"></button>
<button type="button" data-bs-target="#heroCarousel" data-bs-slide-to="1"></button>
<button type="button" data-bs-target="#heroCarousel" data-bs-slide-to="2"></button>
</div>
<!-- slides -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="slide1.jpg" class="d-block w-100" alt="First slide">
<div class="carousel-caption d-none d-md-block">
<h5>First slide</h5>
<p>A caption that hides on phones.</p>
</div>
</div>
<div class="carousel-item">
<img src="slide2.jpg" class="d-block w-100" alt="Second slide">
</div>
<div class="carousel-item">
<img src="slide3.jpg" class="d-block w-100" alt="Third slide">
</div>
</div>
<!-- arrows -->
<button class="carousel-control-prev" type="button"
data-bs-target="#heroCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button"
data-bs-target="#heroCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
The controls and indicators all point back at the wrapper id through data-bs-target, so changing that id means updating it in every child. d-block w-100 on the images stops the inline-image baseline gap and makes slides fill the container — omit both and you get a thin strip of white under each image. The visually-hidden spans give the arrow buttons real labels for screen readers.
Carousel options that matter
| Option | Attribute | What it does |
|---|---|---|
| Autoplay | data-bs-ride="carousel" | Slides automatically; default interval is 5000ms |
| Interval | data-bs-interval="3000" | Milliseconds per slide (per-item attribute) |
| Pause on hover | data-bs-pause="hover" (default) | Stops while the pointer is over it; false never pauses |
| Wrap around | data-bs-wrap="true" (default) | Whether next after the last returns to the first |
| Touch swipe | data-bs-touch="true" (default) | Enables swipe gestures on touch devices |
| Cross-fade | carousel-fade on the wrapper | Fades between slides instead of sliding |
Set data-bs-ride="false" (or drop the attribute) when you want a manual, click-through carousel — the right choice for anything the user must read at their own pace. The cross-fade look is one class: <div id="heroCarousel" class="carousel slide carousel-fade">.
Controlling a carousel from JavaScript
const el = document.getElementById('heroCarousel');
const carousel = bootstrap.Carousel.getOrCreateInstance(el);
carousel.next(); // go forward
carousel.prev(); // go back
carousel.to(2); // jump to slide index 2
carousel.pause(); // stop autoplay
carousel.cycle(); // resume autoplay
// know when a slide has finished
el.addEventListener('slid.bs.carousel', (e) => {
console.log('now on slide', e.to);
});
Call pause() before you open a modal over the carousel and cycle() again when it closes, otherwise the slides keep changing behind the dialog. The events slide.bs.carousel and slid.bs.carousel fire before and after the transition; the event object carries from and to indexes. If you build a full-width slider, the same wrapper works — the Materialize take on that component is in the Materialize carousel guide for comparison.
When the carousel will not slide
- No bundle script. Without
bootstrap.bundle.min.jsthe slides just sit there. - No
activeclass. Exactly onecarousel-itemmust start active; with none, the carousel shows blank. - Uneven slide heights. Give images a fixed aspect ratio or set
object-fit: coverso the page does not jump between slides. - Autoplay not starting. Autoplay needs
data-bs-ride="carousel"; a baredata-bs-ride="true"is not valid and is ignored.
Building the rest of the page around it? The Bootstrap cards guide covers the responsive grid a hero section usually sits above, and the navbar guide covers the navigation that goes on top.
Want a reviewer for a design-heavy build? Ampersand Academy teaches front-end development one-to-one, using your own project as the curriculum.
Frequently asked questions
Why is my Bootstrap carousel not sliding?
The most common cause is a missing bootstrap.bundle.min.js script, since the sliding is JavaScript-driven. Also confirm that exactly one carousel-item has the active class — with none active the carousel shows nothing.
How do I make a Bootstrap carousel start automatically?
Add data-bs-ride set to carousel on the outer carousel div. The default interval is 5000 milliseconds between slides; override it per slide with data-bs-interval in milliseconds.
How do I stop a Bootstrap carousel from autoplaying?
Simply omit data-bs-ride, or set it to false. The carousel then only moves when the user clicks an arrow, a dot, or you call next() or prev() through the JavaScript API.
How do I make a Bootstrap carousel fade instead of sliding?
Add the carousel-fade class alongside slide on the outer carousel div. The slides then cross-fade in place rather than sliding horizontally, using the same controls and indicators.
How do I control a Bootstrap carousel with JavaScript?
Get an instance with bootstrap.Carousel.getOrCreateInstance(element) and call next(), prev(), to(index), pause() or cycle(). Listen for the slid.bs.carousel event to react after each transition finishes.

