Guide to building a dynamic Slick slider complete with a sleek progress bar

I'm looking to customize my slider with a timer pagination feature using progress bars instead of dots, similar to how it is on . Currently, I am using slick.js for my slider implementation.

What is the best way to replace the default pagination buttons with progress bars in my slider?

$(document).ready(function () {
    $('.slider').slick({
        infinite: true,
        autoplay:true,
        dots: true,
        arrows: false,
        autoplaySpeed: 3000,
        slidesToShow: 1,
        slidesToScroll: 1
    });
});
  

.slider .slick-dots {
    padding: 0;
}

.slider .slick-dots li {
    position: relative;
    display: inline-block;
    width: 19%;
    height: 15px;
    margin: 0 2px 0 0;
    padding: 0;
    cursor: pointer;
    background: #ccbdb6;
    transition: width 5s ease-out 0s;
}

.slider .slick-dots li:last-child {
    margin-right: 0;
}

.slider .slick-dots li:hover,
.slider .slick-dots li.slick-active {
    background: #a08a7f;
}

.slider .slick-dots li button {
    display: none !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css"/>

<div class="slider">
  <div>
    <h3>1</h3>
  </div>
  <div>
    <h3>2</h3>
  </div>
  <div>
    <h3>3</h3>
  </div>
  <div>
    <h3>4</h3>
  </div>
  <div>
    <h3>5</h3>
  </div>
</div>

<script type="text/javascript" src="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>

Answer №1

Recently tackled this task at my workplace. It was a bit challenging because our website uses slick with 2 different transitions: swipe with mouse and fade without.

While working on it, I recalled your post and decided to simplify it here.

$(".slider").slick({
  infinite: true,
  arrows: false,
  dots: false,
  autoplay: false,
  speed: 800,
  slidesToShow: 1,
  slidesToScroll: 1,
});

 //ticking machine
    var percentTime;
    var tick;
    var time = 1;
    var progressBarIndex = 0;

    $('.progressBarContainer .progressBar').each(function(index) {
        var progress = "<div class='inProgress inProgress" + index + "'></div>";
        $(this).html(progress);
    });

    function startProgressbar() {
        resetProgressbar();
        percentTime = 0;
        tick = setInterval(interval, 10);
    }

    function interval() {
        if (($('.slider .slick-track div[data-slick-index="' + progressBarIndex + '"]').attr("aria-hidden")) === "true") {
            progressBarIndex = $('.slider .slick-track div[aria-hidden="false"]').data("slickIndex");
            startProgressbar();
        } else {
            percentTime += 1 / (time + 5);
            $('.inProgress' + progressBarIndex).css({
                width: percentTime + "%"
            });
            if (percentTime >= 100) {
                $('.single-item').slick('slickNext');
                progressBarIndex++;
                if (progressBarIndex > 2) {
                    progressBarIndex = 0;
                }
                startProgressbar();
            }
        }
    }

    function resetProgressbar() {
        $('.inProgress').css({
            width: 0 + '%'
        });
        clearInterval(tick);
    }
    startProgressbar();
    // End ticking machine

    $('.progressBarContainer div').click(function () {
    clearInterval(tick);
    var goToThisIndex = $(this).find("span").data("slickIndex");
    $('.single-item').slick('slickGoTo', goToThisIndex, false);
    startProgressbar();
    });
h3 {
  margin:5px 0; 
}

.sliderContainer {
  position: relative;
}

.slider {
  width: 500px;
  margin: 30px 50px 50px;
}

.slick-slide {
  background: #3a8999;
  color: white;
  padding: 80px 0 120px;
  font-size: 30px;
  font-family: "Arial", "Helvetica";
  text-align: center;
}

.slick-prev:before,
.slick-next:before {
  color: black;
}

.slick-dots {
  bottom: -30px;
}

.slick-slide:nth-child(odd) {
  background: #e84a69;
}

.progressBarContainer {
  position: absolute;
  bottom: 20px;
  width:300px;
  left:150px;
}

.progressBarContainer div {
  display: block;
  width: 30%;
  padding: 0;
  cursor: pointer;
  margin-right: 5%;
  float: left;
  color: white;
}

.progressBarContainer div:last-child {
  margin-right: 0;
}

.progressBarContainer div span.progressBar {
  width: 100%;
  height: 4px;
  background-color: rgba(255, 255, 255, 0.4);
  display: block;
}

.progressBarContainer div span.progressBar .inProgress {
  background-color: rgba(255, 255, 255, 1);
  width: 0%;
  height: 4px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js"></script>
<script src="https://rawgit.com/kenwheeler/slick/master/slick/slick.js"></script>
<link href="https://rawgit.com/kenwheeler/slick/master/slick/slick-theme.css" rel="stylesheet"/>
<link href="https://rawgit.com/kenwheeler/slick/master/slick/slick.css" rel="stylesheet"/>

<div class="sliderContainer">
  <div class="slider single-item">
    <div>Slide1</div>
    <div>Slide2</div>
    <div>Slide3</div>
  </div>
  <div class="progressBarContainer">
    <div>
      <h3>Slide 1</h3>
      <span data-slick-index="0" class="progressBar"></span>
    </div>
    <div>
      <h3>Slide 2</h3>
      <span data-slick-index="1" class="progressBar"></span>
    </div>
    <div>
      <h3>Slide 3</h3>
      <span data-slick-index="2" class="progressBar"></span>
    </div>
  </div>
</div>

[codepen][1]

Best Regards,

Answer №2

Despite the abundance of down-votes on this question, I have decided to share my solution here because I find it quite clever.

The solution relies entirely on CSS animations, with each slide featuring a progress bar created using ::after. This progress bar scales from scaleX(0) to scaleX(1) when the slide is .slick-active.

Here is an example:

@keyframes scale-x-zero-to-max {
    0% {
        transform: scaleX(0);
    }

    100% {
        transform: scaleX(1);
    }
}

.slick-slide {
    &:after {
        background: blue;

        display: block;
        content: "";

        width: 100%;
        height: .25rem;

        position: absolute;
        left: 0;
        bottom: 0;
        z-index: 99;

        transform: scaleX(0);
        transform-origin: left 50%;
    }

    &.slick-active:after {
        animation: scale-x-zero-to-max 6s linear .8s 1 forwards; // Note that 6s should be same as Slick's autoplaySpeed and .8s same as speed
    }
}

The only drawback is that there is an issue with the .8s delay on the first slide (it's already visible without spending .8s to slide into view). However, for us, this wasn't a major concern as the slideshow was located below the fold, where most visitors may not even notice. Subsequent slides function correctly after the first slide completes.

Answer №3

I have developed a unique plugin using slick slider that includes a progress bar inside each indicator.

https://github.com/gsushil999/Slick-Slider-Plugin

enter code here

<div class="sliderContainer">
    <div class="slider single-item">
        <div>Slide1</div>
        <div>Slide2</div>
        <div>Slide3</div>
    </div>
    <div class="progressBarContainer">
        <div>

            <span data-slick-index="0" class="progressBar"></span>
        </div>
        <div>

            <span data-slick-index="1" class="progressBar"></span>
        </div>
        <div>

            <span data-slick-index="2" class="progressBar"></span>
        </div>
    </div>
</div>


<script>
    $(".slider").slick({
        infinite: true,
        arrows: false,
        dots: false,
        autoplay: false,
        speed: 500,
        slidesToShow: 1,
        slidesToScroll: 1
    });

    //progress bar logic
    var percentTime;
    var tick;
    var time = 1;
    var progressBarIndex = 0;

    var progress = $('.inProgress');

    $('.progressBarContainer .progressBar').each(function (index) {
        var progress = "<div class='inProgress inProgress" + index + "'></div>";
        $(this).html(progress);
    });

    function startProgressbar() {
        resetProgressbar();
        percentTime = 0;
        tick = setInterval(interval, 10);
    }

    function interval() {
        if (($('.slider .slick-track div[data-slick-index="' + progressBarIndex + '"]').attr("aria-hidden")) === "true") {
            progressBarIndex = $('.slider .slick-track div[aria-hidden="false"]').data("slickIndex");

            console.log(progressBarIndex);

            if (progressBarIndex == 1) {
                $(".inProgress0").addClass('on');
                $(".inProgress1").removeClass('on');
            }
            else if (progressBarIndex == 2) {
                $(".inProgress0").addClass('on');
                $(".inProgress1").addClass('on');
            }
            else if (progressBarIndex == 0) {
                $(".inProgress0").removeClass('on');
                $(".inProgress1").removeClass('on');
            }
            startProgressbar();

        } else {
            percentTime += 1 / (time + 2);
            $('.inProgress' + progressBarIndex).css({
                width: percentTime + "%"
            });
            if (percentTime >= 100) {
                $('.single-item').slick('slickNext');

                //console.log(progressBarIndex);

                if (progressBarIndex == 0) {
                    $(".inProgress0").addClass('on');

                }
                else if (progressBarIndex == 1) {
                    $(".inProgress0").addClass('on');
                    $(".inProgress1").addClass('on');
                }
                else if (progressBarIndex == 2) {
                    $(".inProgress0").removeClass('on');
                    $(".inProgress1").removeClass('on');
                }

                progressBarIndex++;

                if (progressBarIndex > 2) {
                    progressBarIndex = 0;
                }
                startProgressbar();

            }

        }
    }

    function resetProgressbar() {
        $('.inProgress').css({
            width: 0 + '%'
        });
        clearInterval(tick);
    }
    startProgressbar();
    // End progress bar logic

    $('.progressBarContainer div').click(function () {
        clearInterval(tick);
        var goToThisIndex = $(this).find("span").data("slickIndex");
        $('.single-item').slick('slickGoTo', goToThisIndex, false);
        startProgressbar();
    });


</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Show complete items in Vue.js

Issue at hand: I am in need of displaying and potentially changing JSON data. My goal is to present it in a directory tree format. The structure of the object is unknown, it could be something like this: "buttons": { "login": "LOGIN", "register": ...

Calendars malfunctioning following the execution of npm run build

While utilizing the vue2-datepicker for a calendar, I encountered an issue during development. When clicking on the input box in my form, the calendar appeared as expected above the input. However, after running npm run build and loading up the resulting p ...

Obtaining a JavaScript proxy from a WCF service using webHttpBinding

I have configured all the necessary endpoints, bindings, and behaviors to consume a service using JSON. However, I am struggling to find a way to generate a JavaScript proxy for accessing the service from my client-side JavaScript with jQuery through Ajax. ...

The hover effect is not functioning properly after loading jQuery with load();

When loading elements into a div using the load() function, I noticed that the :hover effect in CSS stops working for those elements. It's a dynamic menu setup, as shown below: <div id='main-menu'> <ul> <li class='click ...

Vue component fails to render due to a simple issue

I've been diving into Vue.JS and I'm facing an issue where the component I created isn't showing up on the page. Here's a snippet of my component: import Vue from 'vue' const card = new Vue({ el: '#card', data: ...

Can anyone help me with integrating a search functionality inside a select tag?

I am working on a select dropdown and want to add a search box to easily filter through the available options. I know this can be done using the chosen library, but I prefer to implement it using plain JavaScript or jQuery. Does anyone have suggestions on ...

Tips for adding a new value to an array of objects in React

As I navigate my way through the world of React as a newcomer, I've encountered a challenge that I need some advice on. I am attempting to add a new key and value to an array of objects, but I'm struggling to accomplish this task. Can anyone prov ...

Custom pagination with onSelectionModelChange in React Material UI Data Grid

Has anyone encountered a problem with using the DataGrid component's onSelectionModelChange prop? I can successfully retrieve the selected rows for a single page, but when I implement custom pagination and navigate to the next page, the previous selec ...

What is the best way to prevent jest.mock from being hoisted and only use it in a single jest unit test?

My goal is to create a mock import that will be used only in one specific jest unit test, but I am encountering some challenges. Below is the mock that I want to be restricted to just one test: jest.mock("@components/components-chat-dialog", () ...

Tips for choosing the class=" * " using jQuery's .html() function

Is there a way to target the string "class" or any other specified string within code retrieved from .html()? If we have an element's HTML content stored in another element (similar to a snippet with preview) <div class="myClass">1</div> ...

Are these two sections of my code distinctive in functionality? Do they both address potential errors in the same manner?

After receiving some helpful suggestions on my code from a user on stack overflow, I decided to revisit and make improvements. However, I am now questioning whether the changes I made handle errors in the same way as the original code. This is my initial ...

Angular Controller is not able to retrieve the Route Parameter, resulting in a 404

Currently working on my very first web app using Node.js and AngularJs. I've encountered a roadblock with the following code: var app = angular.module('Martin', ['ngResource','ngRoute']); app.config(['$routeProvide ...

The code functions correctly when retrieving information from a file, however, encounters issues when retrieving data

While working on my React application, I encountered a situation where I needed to read the value for translation from a file stored in the public folder. The files were saved at https://i.sstatic.net/oWXCh.png However, due to the dynamic nature of our d ...

Parsing JSON data to extract values stored in a two-dimensional array

In order to develop a basic version of Tic Tac Toe, I decided to store game data in a JSON file. Here is an example of how the file is structured: [ { "turn": "x", "board": [ [ " ...

JavaScript: Assigning a value to an object using the ID which corresponds to the last letter of the object

Regarding the heading: it may appear confusing at first, but it's actually quite straightforward. Currently in React, I am focusing on code reusability. Here is the initial state: state={ colorObj1: {r:'0',g:'0',b:'0 ...

Guide on sending emails with AngularJS and the Ionic framework

I have been attempting to send an email by using various links, but without success. I am looking for guidance on how to successfully send an email. Below is the code I have been using for sending emails. Any suggestions for changes would be greatly apprec ...

Utilizing Bootstrap 4 to ensure the final DIV is vertically stacked and fills the remaining space in the container

Having trouble creating a responsive layout using Bootstrap 4? Specifically, when two divs wrap vertically on smaller devices, the top div pushes the lower div down, exceeding the parent container. I want the lower div to fit within the container. How can ...

Load Express JS router middleware conditionally based on certain conditions

In my Express JS code, I have implemented a middleware that defines specific end-points on a router for user login and logout. However, I am now integrating a new authentication method where the auth token is received from a different service. In this case ...

Formatting JSON Date Output in a Unique Style

I am sending an api request and I would like to present the date in a similar format to what can be seen at this link: Here is the json data I am receiving: dates: { start: { localDate: "2017-04-06", localTime: "19:31 ...

Cookie Multitree: An Innovative JsTree Solution

Hello everyone, I am currently using jstree and have come across a couple of issues with having multiple trees on the same page. Here are my two problems: 1) I am looking to implement cookies to keep track of which nodes are open in each tree. I attempted ...