Build a mobile-friendly testimonials slideshow

Last updated: October 29, 2021.

Testimonials are a common way to put a spotlight on positive customer feedback. In this tutorial, we will cover how you can create a user-controlled testimonials slideshow using HTML, CSS and JavaScript.

What we will build

Below is a live preview of the project. If you toggle your screen size, you will notice that the slideshow has two fixed views: one for desktop and another for mobile. We will cover how to achieve these using a media query when we add CSS to the project.

See the Pen Untitled by James (@openjavascriptadmin) on CodePen.

Step 1: Create (or get) testimonials data

In a live project, it is likely that testimonial data is fetched from a backend server.

In this tutorial we will create the data ourselves within JavaScript.

To do so, we create an array of JavaScript objects. Each JavaScript object contains the following information: an id (id), the name of the testimonial giver (name) and their testimonial (text) as well as a URL to an image of the testimonial giver (image). User images are randomly generated by the free and open-source Random User Generator API.

Having the data in JavaScript allows us to easily inject it into a web page dynamically.

Step 2: HTML template

We keep this HTML minimal as the testimonial content will be injected using JavaScript.

To wrap the entire content, we create a container div (testimonials-wrapper). This has three children.

The first div contains two Font Awesome quotation marks elements and these will be made the background of the container using CSS. Add the following link to the Font Awesome CDN to make these visible:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"/>

The second child is a testimonial-content div. This is empty. We will inject it with content using JavaScript.

Finally, since they are fixed elements, we place a scroll left (<) and scroll right (>) icon each in their own span elements and place both inside a user-controls-container div.

    <div id="testimonials-wrapper">
        <!-- Background quotation begin -->
        <div>
            <i id="quote-left" class="fas fa-quote-left"></i>
            <i id="quote-right"class="fas fa-quote-right"></i>
        </div>
        <!-- Background quotation end -->
        <!-- Content begins -->
        <div id="testimonial-content"></div>
        <div id="user-controls-container">        
            <span id="scroll-left">&lt;</span>
            <span id="scroll-right">&gt;</span>
        </div>
        <!-- Content ends -->
    </div>

Step 3: Programming slideshow controls with JavaScript

Since our main content is to be injected with JavaScript, we program this first before turning to CSS when we have a full page of content.

We begin by selecting the testimonial-content element, into which we will inject content, and the two user controls arrows.

We then create a global index variable (testimonialIndex) and set its starting value to 0.

We then call the setTestimonial function to inject content onto the page.

The setTestimonial function sets the innerHTML of the empty testimonial-content div to the value of a template string that includes a dynamically injected image, name and testimonial text as follows. The syntax ${testimonials[testimonialIndex].propertyName} gets the property of the object corresponding to the value of testimonialIndex in the earlier defined testimonials data.

So the below code will display the img, name and text property values of the first testimonial inside the empty content-container div as HTML.

        testimonial = document.getElementById('testimonial-content');
        left = document.getElementById('scroll-left');
        right = document.getElementById('scroll-right');

        // Index for setting testimonial
        let testimonialIndex = 0;

        // Load first testimonial (array element "0" of testimonials data)
        setTestimonial();


        function setTestimonial() {
            // Set innerHTML of testimonial content to new template string
            // with content dynamically injected from testimonials data
            testimonial.innerHTML = `
            <img class="thumbnail" src="${testimonials[testimonialIndex].img}">
            <span class="name">${testimonials[testimonialIndex].name}</span>
            <div class="testimonial-text">${testimonials[testimonialIndex].text}</div>
            `
        }

Next, we add user controls so the user can browse through the testimonials.

We do this by adding event listeners to each of the arrows inside the user-controls-container.

If it is right, we add 1 to the global testimonialIndex variables and if left, subtract one.

We then check to see if this makes the value of testimonialIndex out of bounds (i.e. not corresponding to a stored testimonial). If the value of testimonialIndex is now greater than the number of testimonials or less than the index of the first testimonial (-1), the value of testimonialIndex is updated to cycle to the other end of the testimonial list.

Finally, the setTestimonial function is rerun (to update the testimonial content):

        left.addEventListener('click', () => {
            // 1. Subtract 1 from global index variable
            testimonialIndex--;
            // 2. Check if index is -1 (out of bounds). If so, set to
            // length of testimonals data -1 (final testimonial)
            if (testimonialIndex == -1) {testimonialIndex = testimonials.length-1}
            // 3. Set testimonial with updated index variable
            setTestimonial();
        })

        right.addEventListener('click', () => {
            // 1. Add 1 to global index variable
            testimonialIndex++;
            // 2. Check if index is the length of testimonials data (out of bounds). 
            // If so, set to 0 (first testimonial)
            if (testimonialIndex == testimonials.length) {testimonialIndex = 0}
            // 3. Set testimonial with updated index variable
            setTestimonial();
        })

Step 4: Add responsive CSS

Apply the following CSS for the same appearance as the live preview.

The main features of the CSS:

  • Vertical alignment of the contents by applying a vertical flexbox to testimonials-wrapper
  • Quotation elements have display: absolute applied to they are ‘under’ the content
  • User controls arrows centered by applying a horizontal flexbox to user-controls-container
  • A fixed mobile-view of 280px width and 370px height
  • A fixed large-screen-view (>650px) of 550px width and 370px height
        /*** Mobile layout ***/
        body {
            background-color: whitesmoke;
            font-family: Arial;
        }
        #testimonials-wrapper {
            display: flex;
            flex-direction: column; /* format content vertically */
            justify-content: space-between;
            background-color: white;
            border: 0.1rem lightgray solid;
            border-radius: 0.3rem;
            box-shadow: 10px 5px 5px lightgray;
            padding: 0.5rem;
            width: 280px; /* fixed width */
            height: 370px; /* fixed height */
            margin: auto;
            margin-top: 4rem;
        }
        #testimonial-content { /* div into which content is injected by JS */
            font-size: 1rem;
            padding: 1rem;
            padding-bottom: 0.2rem;
            text-align: center;
        }
        .thumbnail {
            display: block;
            margin: auto;
            width: 100px;
            border-radius: 10rem;
            padding: 0.1rem;
        }
        .testimonial-text {
            padding: 0.5rem;
            padding-left: 0.1rem;
            padding-right: 0.1rem;
            font-size: 0.9rem;
            text-align: center;
        }
        .name {
            font-weight: 900;
        }
        #user-controls-container { /* centers contained arrows */
            display: flex;
            flex-direction: row;
            justify-content: center;
        }
        #scroll-left, #scroll-right {
            text-align: center;
            font-size: 1.2rem;
            padding: 0rem;
            margin: 0rem;
            color: steelblue;
            font-weight: 900;
            margin-left: 1rem; /* margin-left and margin-right create arrow spacing */
            margin-right: 1rem;
        }
        #quote-left {
            display: block;
            position: absolute;
            color:rgb(176, 196, 222, 0.2);
            font-size: 100px;
        }
        #quote-right {
            display: block;
            position: absolute;
            color:rgb(176, 196, 222, 0.2);
            font-size: 100px;
            margin-left: 180px;
            margin-top: 220px;
        }

        /*** Adjustment for desktop ***/

        @media screen and (min-width: 650px) {
        #testimonials-wrapper {
            width: 550px;
        }
        .thumbnail {
            width: 120px;
        }
        #testimonial-content {
            font-size: 1.2rem;
        }
        .testimonial-text {
            font-size: 1rem;
        }
        #quote-right {
            margin-left: 440px;
            margin-top: 170px;
        }
        }

Summary

In this tutorial, we have seen how to create a testimonials slideshow with user controls using HTML, CSS and plain JavaScript.

If you enjoyed this tutorial, good news. We have more free projects on our projects page!