Skip to main content

Carousel

A slideshow built on CSS scroll snapping: the browser handles sliding, swiping and momentum, and bootstrap-ng handles the active slide, controls, keyboard and autoplay.

Bootstrap’s carousel docs describe the markup and CSS.

Example

Put bsCarouselItem slides in a .carousel-inner. bsCarouselPrev and bsCarouselNext can go anywhere inside the carousel. Give the carousel an aria-label. Focus the carousel and use the arrow keys to move between slides. Screen readers announce the new slide, except while autoplay is on.

HTML
<div bsCarousel aria-label="Basic carousel">
  <div class="carousel-inner">
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        First slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-3"
        style="height: 240px">
        Second slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        Third slide
      </div>
    </div>
  </div>
  <div class="d-flex justify-content-end mt-2">
    <div>
      <button type="button" class="btn-icon btn-sm" bsCarouselPrev>
        <span class="carousel-icon-prev" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
      </button>
      <button type="button" class="btn-icon btn-sm" bsCarouselNext>
        <span class="carousel-icon-next" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
      </button>
    </div>
  </div>
</div>

Indicators

Add bsCarouselIndicator buttons with the slide index in a .carousel-indicators element. Bind [(active)] to read or set the active slide.

Active slide: 1

<div bsCarousel aria-label="Carousel with indicators" [(active)]="slide">
  <div class="carousel-inner">
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        First slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-3"
        style="height: 240px">
        Second slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        Third slide
      </div>
    </div>
  </div>
  <div class="d-flex justify-content-between align-items-center mt-2">
    <div>
      <button type="button" class="btn-icon btn-sm" bsCarouselPrev>
        <span class="carousel-icon-prev" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
      </button>
      <button type="button" class="btn-icon btn-sm" bsCarouselNext>
        <span class="carousel-icon-next" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
      </button>
    </div>
    <div class="carousel-indicators">
      @for (i of [0, 1, 2]; track i) {
        <button
          type="button"
          [bsCarouselIndicator]="i"
          [attr.aria-label]="`Slide ${i + 1}`"></button>
      }
    </div>
  </div>
</div>
<p class="mt-2 mb-0">Active slide: {{ slide() + 1 }}</p>

Overlay controls and crossfade

Add .carousel-overlay and wrap controls in .carousel-overlay-controls to place them over the slides. Add .carousel-fade to crossfade instead of sliding.

HTML
<div bsCarousel class="carousel-overlay carousel-fade" aria-label="Crossfading carousel">
  <div class="carousel-inner">
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        First slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-3"
        style="height: 240px">
        Second slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        Third slide
      </div>
    </div>
  </div>
  <div class="carousel-overlay-controls">
    <button type="button" class="btn-icon btn-sm" bsCarouselPrev>
      <span class="carousel-icon-prev" aria-hidden="true"></span>
      <span class="visually-hidden">Previous</span>
    </button>
    <button type="button" class="btn-icon btn-sm" bsCarouselNext>
      <span class="carousel-icon-next" aria-hidden="true"></span>
      <span class="visually-hidden">Next</span>
    </button>
  </div>
</div>

Autoplay

autoplay cycles through the slides every interval milliseconds, pausing on hover and while the page is hidden. Using a control, an indicator, the keyboard or swiping stops autoplay for good. Always add a bsCarouselPlayPause button, as WCAG 2.2.2 requires a way to pause moving content.

HTML
<div bsCarousel autoplay [interval]="4000" aria-label="Autoplaying carousel">
  <div class="carousel-inner">
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        First slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-3"
        style="height: 240px">
        Second slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        Third slide
      </div>
    </div>
  </div>
  <div class="d-flex justify-content-between align-items-center mt-2">
    <div class="carousel-indicators">
      @for (i of [0, 1, 2]; track i) {
        <button
          type="button"
          [bsCarouselIndicator]="i"
          [attr.aria-label]="`Slide ${i + 1}`"></button>
      }
    </div>
    <div>
      <button type="button" class="btn-icon btn-sm" bsCarouselPlayPause>
        <span class="carousel-icon-pause" aria-hidden="true"></span>
        <span class="carousel-icon-play" aria-hidden="true"></span>
      </button>
      <button type="button" class="btn-icon btn-sm" bsCarouselPrev>
        <span class="carousel-icon-prev" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
      </button>
      <button type="button" class="btn-icon btn-sm" bsCarouselNext>
        <span class="carousel-icon-next" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
      </button>
    </div>
  </div>
</div>

End behavior

By default (ends="loop") the carousel keeps sliding in the same direction past the last or first slide, onto the other end. wrap jumps back instead, which is also what loop does for layouts showing several slides and for users who prefer reduced motion. With ends="stop", shown here, the carousel stops at the first and last slide and disables the previous or next button there, moving focus to the other one.

HTML
<div bsCarousel ends="stop" aria-label="Carousel that stops at the ends">
  <div class="carousel-inner">
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        First slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-3"
        style="height: 240px">
        Second slide
      </div>
    </div>
    <div bsCarouselItem>
      <div
        class="d-flex align-items-center justify-content-center rounded-5 bg-2"
        style="height: 240px">
        Third slide
      </div>
    </div>
  </div>
  <div class="d-flex justify-content-end mt-2">
    <div>
      <button type="button" class="btn-icon btn-sm" bsCarouselPrev>
        <span class="carousel-icon-prev" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
      </button>
      <button type="button" class="btn-icon btn-sm" bsCarouselNext>
        <span class="carousel-icon-next" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
      </button>
    </div>
  </div>
</div>

API

BsCarousel

Selector: [bsCarousel] · Exported as: bsCarousel

Inputs

NameTypeDefaultDescription
activenumber0Index of the active slide. Supports [(active)].
autoplaybooleanfalseCycles through the slides.
intervalnumber5000Milliseconds between slides while playing.
pauseOnHoverbooleantruePauses autoplay while the pointer is over the carousel.
ends'loop' | 'wrap' | 'stop''loop'What happens past the first and last slide.
keyboardbooleantrueMoves between slides with the arrow keys.
idstringgeneratedElement id, used by the controls for aria-controls.

Outputs

NameTypeDescription
activeChangenumberEmits the new active slide index.

Methods

NameTypeDescription
next()voidShows the next slide.
prev()voidShows the previous slide.
to(index)voidShows the slide at index.
play()voidStarts autoplay.
pause()voidStops autoplay.
isPlayingSignal<boolean>Whether autoplay is on.
countSignal<number>Number of slides.
lastIndexSignal<number>Index of the last slide that can scroll to the start. Lower than count - 1 when several slides are visible.

BsCarouselItem

Selector: [bsCarouselItem] · Exported as: bsCarouselItem

BsCarouselPrev

Selector: [bsCarouselPrev]

BsCarouselNext

Selector: [bsCarouselNext]

BsCarouselIndicator

Selector: [bsCarouselIndicator]

Inputs

NameTypeDefaultDescription
bsCarouselIndicatornumberrequiredIndex of the slide it shows.
aria-labelstringSlide nAccessible label.

BsCarouselPlayPause

Selector: [bsCarouselPlayPause]

Inputs

NameTypeDefaultDescription
pauseLabelstring'Pause'Accessible label while playing.
playLabelstring'Play'Accessible label while paused.