How to Create a Bootstrap 5 Testimonial Slider

How to Create a Bootstrap 5 Testimonial Slider

Bootstrap 5 testimonial slider using Swiper.js, explains the markup patterns that matter for SEO and screen readers, and covers the ready-built blocks available inside the Canvas HTML Template if you need to ship faster.

Key Takeaways

  • Bootstrap 5 has no built-in slider beyond its basic Carousel; a dedicated library like Swiper.js (v11) is the right tool for testimonial carousels with per-slide navigation.
  • Semantic markup using blockquote, figure, and figcaption improves accessibility and gives search engines structured review signals.
  • CSS custom properties (including Bootstrap’s own --bs-* tokens) let you theme the slider without touching core files.
  • Canvas Template ships pre-built testimonial blocks across its 50-plus demos, saving significant build time for agencies.
  • Auto-play without a pause mechanism fails WCAG 2.1 Success Criterion 2.2.2; the pattern below includes a pause button.

Bootstrap 5’s built-in .carousel component is designed for full-width image rotators. It works, but repurposing it as a testimonial carousel brings real costs:

  • No native multi-slide-per-view support without significant CSS overrides.
  • No loop mode without JavaScript duplication hacks.
  • Pagination dots are not built in; you must write custom indicator markup.
  • Touch/swipe support is basic compared to dedicated sliders.

If all you need is a single-quote auto-advance with simple prev/next arrows, the native carousel is fine. For anything beyond that (responsive breakpoints, centered active slide, autoplay with pause) reach for Swiper.js. At around 39 KB minified and gzipped in its modular form, it adds minimal weight. The post on building a Bootstrap 5 image carousel with custom controls covers the native component in full if you want a deeper comparison.

testimonial carousel html, abstract technical diagram

Project Setup: Bootstrap 5 and Swiper.js

Add Bootstrap 5 (version 5.3.x) and Swiper 11 via CDN, or install both with npm if you are using a build pipeline.

<!-- Bootstrap 5.3 CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">

<!-- Swiper 11 CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css">

<!-- Bootstrap 5.3 JS (bundle includes Popper) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

<!-- Swiper 11 JS -->
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

If you are working inside Canvas Template, Swiper is already bundled in plugins.min.js, so you skip the CDN links and initialise through the data-* API that functions.bundle.js exposes.

Semantic HTML Markup for the Testimonial Carousel

Use figure and blockquote rather than generic div elements. Search engines and screen readers both benefit, and the testimonial carousel HTML becomes easier to maintain.

<section class="py-5 bg-light" aria-label="Customer testimonials">
  <div class="container">
    <div class="swiper testimonial-swiper">
      <div class="swiper-wrapper">

        <!-- Slide 1 -->
        <figure class="swiper-slide text-center px-4 mb-0">
          <blockquote class="blockquote">
            <p class="fs-5 fst-italic text-muted">"Canvas cut our build time in half. The pre-built sections are exactly what we needed for a client launch."</p>
          </blockquote>
          <figcaption class="blockquote-footer mt-3">
            <img src="avatar-1.webp" alt="Sarah K." width="56" height="56"
                 class="rounded-circle me-2" loading="lazy">
            Sarah K., <cite>Lead Developer, Acme Agency</cite>
          </figcaption>
        </figure>

        <!-- Slide 2 -->
        <figure class="swiper-slide text-center px-4 mb-0">
          <blockquote class="blockquote">
            <p class="fs-5 fst-italic text-muted">"The dark mode support alone saved us two days of custom CSS. Highly recommended."</p>
          </blockquote>
          <figcaption class="blockquote-footer mt-3">
            <img src="avatar-2.webp" alt="James O." width="56" height="56"
                 class="rounded-circle me-2" loading="lazy">
            James O., <cite>Freelance Designer</cite>
          </figcaption>
        </figure>

        <!-- Slide 3 -->
        <figure class="swiper-slide text-center px-4 mb-0">
          <blockquote class="blockquote">
            <p class="fs-5 fst-italic text-muted">"Our SaaS landing page went from wireframe to live in three days. The Canvas demos gave us the perfect starting point."</p>
          </blockquote>
          <figcaption class="blockquote-footer mt-3">
            <img src="avatar-3.webp" alt="Priya M." width="56" height="56"
                 class="rounded-circle me-2" loading="lazy">
            Priya M., <cite>Product Manager, StartupCo</cite>
          </figcaption>
        </figure>

      </div>

      <!-- Pagination -->
      <div class="swiper-pagination mt-4"></div>

      <!-- Navigation -->
      <button class="swiper-button-prev" aria-label="Previous testimonial"></button>
      <button class="swiper-button-next" aria-label="Next testimonial"></button>

      <!-- Accessible pause button -->
      <div class="text-center mt-3">
        <button id="testimonial-pause" class="btn btn-sm btn-outline-secondary">Pause</button>
      </div>
    </div>
  </div>
</section>

The loading="lazy" attribute on avatar images is a quick Core Web Vitals win for off-screen slides. The broader strategy is covered in the guide on optimising Bootstrap 5 images for Core Web Vitals.

JavaScript Initialisation with Autoplay and Pause

Initialise Swiper after the DOM is ready. The configuration below targets a single slide per view on mobile, two on tablet, and three on desktop, with loop mode and keyboard navigation enabled.

<script>
  const testimonialSwiper = new Swiper('.testimonial-swiper', {
    loop: true,
    centeredSlides: true,
    autoplay: {
      delay: 5000,
      disableOnInteraction: false,
    },
    keyboard: {
      enabled: true,
    },
    pagination: {
      el: '.swiper-pagination',
      clickable: true,
    },
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev',
    },
    breakpoints: {
      576: { slidesPerView: 1, spaceBetween: 24 },
      768: { slidesPerView: 2, spaceBetween: 32 },
      992: { slidesPerView: 3, spaceBetween: 40 },
    },
  });

  // WCAG 2.1 SC 2.2.2: provide pause control
  const pauseBtn = document.getElementById('testimonial-pause');
  let paused = false;
  pauseBtn.addEventListener('click', () => {
    paused = !paused;
    paused ? testimonialSwiper.autoplay.stop() : testimonialSwiper.autoplay.start();
    pauseBtn.textContent = paused ? 'Resume' : 'Pause';
    pauseBtn.setAttribute('aria-pressed', paused);
  });
</script>

Setting disableOnInteraction: false ensures autoplay resumes after the user swipes. That is almost always the right behaviour for testimonial carousels, where a user swiping once should not permanently kill rotation.

Styling with CSS Custom Properties

Bootstrap 5 exposes its own --bs-* tokens. Pair them with your own variables for a consistent theme without forking any source files. Canvas extends this system with --cnvs-themecolor.

<style>
  :root {
    --testimonial-accent: var(--cnvs-themecolor, #0d6efd);
  }

  .testimonial-swiper .swiper-pagination-bullet-active {
    background-color: var(--testimonial-accent);
  }

  .testimonial-swiper .swiper-button-next,
  .testimonial-swiper .swiper-button-prev {
    color: var(--testimonial-accent);
  }

  .testimonial-swiper figure {
    background: var(--bs-white);
    border-radius: 0.75rem;
    padding: 2rem;
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
  }
</style>

For a deeper look at choosing between SCSS and CSS variables for theming, see SCSS vs CSS Variables for Theming Bootstrap 5.

Using Pre-Built Testimonial Blocks in Canvas Template

Canvas ships dedicated review and testimonial section blocks across its 50-plus demos: multi-column grid layouts, full-width quote sliders, and star-rating variants. Blocks initialise automatically via the data-plugin="swiper" attribute wired to functions.bundle.js, so there is no manual JavaScript to write.

Key Canvas testimonial block features:

  • Star rating icons using the included icon font, no extra HTTP requests.
  • Avatar images with optional lazy loading via Canvas’s built-in lazy-load helper.
  • Dark section variants that respect the --cnvs-themecolor override without extra CSS.
  • RTL layout support for right-to-left language sites, enabled by a single HTML attribute.

For agencies shipping multiple client sites, having these blocks pre-tested removes a real QA burden. The approach mirrors how Canvas handles team member layouts, covered in the guide to Canvas team section blocks for about pages.

Common Mistakes to Avoid

  • Forgetting loop: true compensation. Swiper clones slides in loop mode. If you dynamically insert slides after init, call testimonialSwiper.update() to rebuild the clones.
  • Missing ARIA labels on navigation buttons. Swiper’s default rendered buttons have no visible text label. Always add aria-label as shown above.
  • Auto-play without pause. WCAG 2.1 SC 2.2.2 requires a mechanism to pause, stop, or hide any moving content that lasts more than five seconds. The pause button in the code above satisfies this.
  • Loading all Swiper modules in a bundle. If you use npm, import only the modules you need (Navigation, Pagination, Autoplay, Keyboard) to keep bundle size down. The CDN bundle approach is acceptable for prototypes but inefficient for production.
  • Not setting explicit width and height on avatar images. Omitting these causes layout shift during load, harming Cumulative Layout Shift scores. Use the width and height attributes as shown in the markup above.

Frequently Asked Questions

Yes, but with limitations. The native Bootstrap Carousel supports one slide at a time, has no built-in pagination dots, and lacks native touch-swipe fidelity on mobile. For a simple single-quote rotator it is sufficient. For multi-slide-per-view layouts or smooth loop behaviour, Swiper.js is the better choice. Both approaches are valid depending on your requirements.

Testimonial text inside a slider is typically crawlable by Googlebot if it is rendered in HTML (not injected via JavaScript after a long delay). Using semantic blockquote and cite elements adds structured meaning. For rich snippet eligibility you would also need to add Review schema markup via JSON-LD, which is separate from the HTML slider markup shown here.

Four steps cover the main requirements: add descriptive aria-label attributes to navigation buttons, include a visible pause control to satisfy WCAG 2.1 SC 2.2.2, enable keyboard navigation (Swiper’s keyboard: { enabled: true } option handles arrow keys), and wrap the slider in a landmark element with a descriptive aria-label such as “Customer testimonials”.

Swiper is framework-agnostic and has no Bootstrap dependency; any version from 8 onwards works alongside Bootstrap 5. This guide uses Swiper 11, which is the current stable release as of 2025. The API between versions 8 and 11 is largely compatible, though version 9 changed some parameter names (notably spaceBetween moved into breakpoints). Check the Swiper changelog if you upgrade from an older project.

Canvas uses a data-attribute API defined in functions.bundle.js. You add data-plugin="swiper" to the slider container along with data-swiper-options='{"loop":true,"autoplay":{"delay":5000}}' (a JSON string). The bundled script reads these attributes on DOM ready and initialises Swiper automatically. This means designers can configure sliders entirely in HTML without writing JavaScript, which is useful for agencies working with non-developer team members.

Looking for a production-ready Bootstrap 5 HTML template? Browse Canvas Template demos and find the perfect starting point for your next project.

If you’re building with the Canvas HTML Template and want to ship production-ready Bootstrap 5 layouts faster, try Canvas Builder free — the visual builder that exports clean Canvas-ready markup in minutes.

Skip the setup and build it free

Spin up a complete Bootstrap 5 site, blog included, with Canvas Builder. No coding, no cost.

Share:
Canvas Team
Canvas Team

Tutorials and tips for building beautiful Bootstrap 5 websites with the Canvas HTML Template and Canvas Builder.

More from the Canvas Blog