Skip to content
Testimonial Widget
Menu

A jQuery testimonial slider, with no plugin

A testimonial slider in one short jQuery script, with a live demo, code to copy, and a note on Slick and Owl Carousel.

Published

If your site already loads jQuery, a testimonial slider takes one short script and no plugin. This guide has the code, a demo that runs it, and a note on the slider plugins many older tutorials use.

What it looks like

One testimonial shows at a time, and the buttons fade to the next. The testimonials are samples written for this guide.

The code

Paste this where the slider should appear. It was tried with jQuery 4.0.0 and with jQuery 3.7.1.

Testimonial slider: HTML, CSS and jQuery

<!-- Sample testimonials. Replace them with your customers' own words. -->
<section class="tq" aria-label="Customer testimonials">
  <div class="tq-slides" aria-live="polite">
    <figure class="tq-slide">
      <blockquote>“They rebuilt our booking page in a week. Online bookings went from four a week to eleven.”</blockquote>
      <figcaption><strong>Dana R.</strong> Studio owner, Leeds</figcaption>
    </figure>
    <figure class="tq-slide">
      <blockquote>“I expected to wait days for an answer. The reply came in an hour, and it fixed the problem.”</blockquote>
      <figcaption><strong>Tomás G.</strong> Shop manager, Valencia</figcaption>
    </figure>
    <figure class="tq-slide">
      <blockquote>“We had tried two other suppliers. This is the first one that delivered on the day it promised.”</blockquote>
      <figcaption><strong>Aiko M.</strong> Café owner, Osaka</figcaption>
    </figure>
    <figure class="tq-slide">
      <blockquote>“Clear quote, no surprises on the invoice, and the work was finished a day early.”</blockquote>
      <figcaption><strong>Priya S.</strong> Homeowner, Pune</figcaption>
    </figure>
  </div>
  <div class="tq-controls">
    <button type="button" class="tq-prev">Previous</button>
    <span class="tq-count"></span>
    <button type="button" class="tq-next">Next</button>
  </div>
</section>

<style>
  .tq {
    --tq-accent: #2440d9; /* buttons */
    max-width: 40rem;
    margin: 0 auto;
    text-align: center;
  }
  .tq-slide {
    margin: 0 0 1.5rem;
  }
  .tq-slide blockquote {
    margin: 0 0 1rem;
    font-size: 1.25rem;
    line-height: 1.5;
  }
  .tq-slide figcaption {
    color: #5c6370;
  }
  .tq-slide strong {
    display: block;
    color: #1b2033;
  }
  /* Once the script is running, one slide shows at a time, in a box of steady height. */
  .tq-ready .tq-slides {
    min-height: 11rem; /* room for your longest testimonial, so the buttons stay put */
  }
  .tq-controls {
    display: none;
    justify-content: center;
    align-items: center;
    gap: 1rem;
  }
  .tq-ready .tq-controls {
    display: flex;
  }
  .tq-controls button {
    padding: 0.5rem 1rem;
    border: 1.5px solid var(--tq-accent);
    border-radius: 6px;
    background: transparent;
    color: var(--tq-accent);
    font: inherit;
    cursor: pointer;
  }
  .tq-controls button:hover {
    background: var(--tq-accent);
    color: #ffffff;
  }
</style>

<script>
  jQuery(function ($) {
    // jQuery's slim build has no effects. Without them, leave every testimonial showing.
    if (!$.fn.fadeIn) return;
    var still = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    $(".tq").each(function () {
      var $slider = $(this);
      var $slides = $slider.find(".tq-slide");
      var $count = $slider.find(".tq-count");
      var current = 0;

      function show(index) {
        current = (index + $slides.length) % $slides.length;
        $slides.stop(true, true).hide();
        $slides.eq(current).fadeIn(still ? 0 : 300);
        $count.text(current + 1 + " of " + $slides.length);
      }

      $slider.find(".tq-prev").on("click", function () {
        show(current - 1);
      });
      $slider.find(".tq-next").on("click", function () {
        show(current + 1);
      });

      $slider.addClass("tq-ready");
      show(0);
    });
  });
</script>

If the page does not load jQuery yet

WordPress sites and older Bootstrap sites usually do. If yours does not, this is jQuery's own line for loading it. Put it before the slider's script.

jQuery: script tag

<script src="https://code.jquery.com/jquery-4.0.0.min.js" integrity="sha256-OaVG6prZf4v69dPg6PhVattBXkcOWQB62pdZ3ORyrao=" crossorigin="anonymous"></script>

Use the full build of jQuery. Its "slim" build leaves out the effects that the fade depends on. With the slim build the script steps aside, and every testimonial shows at once.

How it works

  • Every testimonial is on the page. Each is a figure inside .tq-slides. If jQuery or the script does not load, they all show, one under another, and nothing is lost.
  • The script hides all but one. show() hides every slide and fades in the one whose turn it is. Past the last slide it goes back to the first.
  • The buttons appear only when they work. They are hidden until the script adds the class tq-ready to the slider.
  • It stays still until asked. There is no timer. A testimonial stays for as long as the visitor wants to read it.
  • It respects reduced motion. For visitors who have asked their device to reduce motion, the slide changes without the fade.
  • A screen reader hears the change. aria-live="polite" on the slides tells it to read the new testimonial after a button is pressed.

Make it yours

  • Your testimonials. Copy a whole block from <figure class="tq-slide"> to </figure> to add one. Use what the customer wrote, with their agreement.
  • Colour. Change --tq-accent at the top of the styles.
  • Height. min-height on .tq-ready .tq-slides keeps the buttons from moving when a short testimonial follows a long one. Raise it until your longest testimonial fits on a phone.
  • Speed. The 300 in fadeIn is the length of the fade in milliseconds.
  • More than one slider. The script handles every element with the class tq on the page, each with its own count.

What about Slick and Owl Carousel?

Many tutorials for a jQuery testimonial slider use a plugin, most often Slick or Owl Carousel. The two are not equally looked after: Slick had a new release in July 2026, and Owl Carousel's last was in April 2018. Check when a plugin last had a release before you build on it. A slider that shows one quote at a time needs neither, and the code above has nothing to update but jQuery itself.

If you want several cards side by side that the visitor swipes through, you do not need jQuery at all: the HTML testimonial slider does that with CSS. On a Bootstrap site, the Bootstrap testimonial slider uses the carousel Bootstrap already has.

What hand-written code does not do

  • Every change is an edit. A new testimonial means opening the page and changing the HTML.
  • Nothing is collected for you. You gather the quotes, the names and the permissions yourself.
  • Reviews do not come in on their own. Reviews on Google or another site have to be typed in, and they do not update.

If you would rather keep your testimonials in one list and change them without touching the page, build the widget instead. A carousel can be published on ReTestimonial's free plan with up to 10 testimonials, and a slider shows one testimonial at a time, as this code does. Either goes into a page as one snippet: see the steps for plain HTML or WordPress.