Skip to content
UI ComponentCardsUI ElementNew

Interactive Product Cart Auto Sliding Carousel

A responsive Infinite Product Carousel built with HTML, CSS, and vanilla JavaScript. Features dynamic product cards, autoplay, smooth transitions, infinite-style navigation, pagination dots, wishlist toggles, Add to Cart interactions, discount badges, and responsive layouts for desktop, tablet, and mobile devices. Lightweight, interactive, and easy to integrate into e-commerce websites.

  • Published 5 Nov 2026
  • 1 views
This cover shows the auto sliding carousel which slides each 3 seconds automatically

Overview

Interactive Product Carousel with Shopping Cart

A responsive product carousel built using HTML, CSS, and vanilla JavaScript. It features automatic sliding, navigation controls, dynamic product pricing, wishlist toggling, and Add to Cart notifications.

What's Included

  • index.html — Product carousel structure
  • style.css — Styling and responsive layout
  • script.js — Product rendering, navigation, autoplay, wishlist, and notifications

Dependencies

  • HTML5
  • CSS3
  • Vanilla JavaScript

No external JavaScript libraries or frameworks are required.

Desktop Preview

Live Demo: https://auto-slider-infi.netlify.app/

HTML

html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Document</title>
7    <script src="https://kit.fontawesome.com/1935d064dd.js" crossorigin="anonymous"></script>
8    <link rel="stylesheet" href="style.css">
9</head>
10<body>
11    <h1>Product Slider</h1>
12    <main>
13        <div class="slide-container">
14            
15        <img id="slide-left" class="arrow" src="images/left red.png">
16    <section class="container" id="slider" tabindex="0"
17         aria-label="Product carousel"></section>
18    <img id="slide-right" class="arrow" src="images/right red.jpg">
19</div>
20<button id="autoplay-toggle" type="button" aria-label="Pause automatic sliding">
21    Pause
22</button>
23<div class="autoplay-progress" aria-hidden="true">
24    <div id="autoplay-progress-fill"></div>
25</div>
26<div id="cart-toast" class="cart-toast" role="status" aria-live="polite"></div>
27</main>
28    
29
30    <script src="script.js"></script>
31</body>
32</html>

CSS

css
1@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap');
2
3
4:root {
5    --white: #fff;
6    --black: #1c2b2d;
7    --blue: #31326f;
8    --color-primary: #9d0191;
9    --color-sec: #db6400;
10    --color-grey: #eee;
11    --color-dark-grey: #222831;
12}
13
14* {
15    margin: 0;
16    padding: 0;
17    box-sizing: border-box;
18}
19
20body {
21    font-family: 'Open Sans', sans-serif;
22    padding-top: 3rem;
23}
24
25/* UTILITY */
26.p-small {
27    padding-bottom: 5px;
28}
29.p-medium {
30    padding-bottom: 10px;
31}
32.p-y {
33    padding: 10px 0;
34}
35.m-y {
36    margin: 10px 0;
37}
38
39p {
40    font-size: 1.6rem;
41    line-height: 1.5;
42}
43
44img {
45    width: 100%; 
46}
47
48.container {
49    max-width: 1200px;
50    margin: 0 auto;
51    /* padding: 0 20px; */
52}
53
54h1 {
55    font-size: 3rem;
56    line-height: 2;
57    text-align: center;
58    color: var(--color-primary);
59}
60
61main {
62
63    background-color: #f4f4f4;
64    padding: 4rem 0;
65    
66}
67
68.slide-container {
69    max-width: 1000px;
70    display: flex;
71    justify-content: center;
72    align-items: center;
73    margin: 0 auto;
74}
75
76.arrow {
77    width: 2rem;
78    margin: 0 1rem;
79}
80
81section {
82    width: 100%;
83    /* height: 300px; */
84    margin: 0 auto;
85    display: flex;
86    justify-content: flex-start;
87    align-items: center;
88    flex-wrap: nowrap;
89    overflow-x: auto;
90    -webkit-overflow-scrolling: touch;
91    /* border: 1px solid black; */
92}
93
94section::-webkit-scrollbar {
95    height: 5px;
96    width: 2px;
97    border: 1px solid #d5d5d5;
98    background: #d5d5d5;
99}
100
101section::-webkit-scrollbar-track {
102    --webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
103}
104
105section::-webkit-scrollbar-thumb {
106    background-color: var(--color-primary);
107    outline: 1px solid #eee;
108     /* border-radius: 100px; */
109  }
110
111section .thumbnail {
112    flex: 0 0 auto;
113	object-fit: contain;
114    width: 200px;
115    height: 300px;
116    display: block;
117    position: relative;
118	cursor: pointer;
119	margin: 5px;
120    border: 2px solid var(--black);
121    overflow: hidden;
122    transform: scale(.95);
123    transition: all .3s;
124}
125section .thumbnail img {
126    display: block;
127    width: 100%;
128    height: 200px;
129    object-fit: contain;
130}
131
132section .thumbnail:hover {
133    transform: scale(1);
134}
135
136.product-details {
137    text-align: center;
138    padding-bottom: 1rem;
139    background-color: #fff;
140}
141
142.product-details h2 {
143    font-size: 1.2rem;
144    font-weight: 500;
145}
146
147.product-details p {
148    font-size: 1rem;
149    padding-bottom: 1rem;
150    color: green;
151    font-weight: 700;
152}
153
154.product-details p span {
155    text-decoration: line-through;
156    color: red;
157    font-weight: normal;
158}
159
160.product-details button {
161    font-size: 1rem;
162    background-color: var(--color-sec);
163    color: #fff;
164    padding: .5rem 1rem;
165    border-radius: 3px;
166    border: 0;
167    cursor: pointer;
168}
169
170.product-details button:hover {
171    background-color: var(--color-primary);
172}
173@media (max-width: 768px) {
174    section .thumbnail {
175        flex-basis: calc((100% - 10px) / 2);
176    }
177}
178
179@media (max-width: 480px) {
180    section .thumbnail {
181        flex-basis: 100%;
182    }
183}
184.discount-badge {
185    position: absolute;
186    top: 8px;
187    left: 8px;
188    z-index: 1;
189    padding: 5px 8px;
190    border-radius: 4px;
191    background-color: var(--color-primary);
192    color: white;
193    font-size: 0.8rem;
194    font-weight: 700;
195}
196#autoplay-toggle {
197    display: block;
198    margin: 12px auto 0;
199    padding: 8px 16px;
200    cursor: pointer;
201    color:#9d0191;
202    background-color:#d8d8d8;
203}
204
205#autoplay-toggle:focus-visible {
206    outline: 3px solid var(--color-sec);
207    outline-offset: 3px;
208    
209}
210
211.wishlist-toggle {
212    position: absolute;
213    top: 10px;
214    right: 10px;
215    z-index: 2;
216    width: 36px;
217    height: 36px;
218    border: 0;
219    border-radius: 50%;
220    background: white;
221    color: var(--color-dark-grey);
222    font-size: 1.3rem;
223    cursor: pointer;
224}
225
226.wishlist-toggle[aria-pressed="true"] {
227    color: #d11a5b;
228}
229
230.wishlist-toggle:focus-visible,
231.product-details button:focus-visible {
232    outline: 3px solid var(--color-sec);
233    outline-offset: 3px;
234}
235
236.autoplay-progress {
237    width: min(300px, 80%);
238    height: 6px;
239    margin: 10px auto 0;
240    overflow: hidden;
241    border-radius: 999px;
242    background: #d8d8d8;
243}
244
245#autoplay-progress-fill {
246    width: 0;
247    height: 100%;
248    border-radius: inherit;
249    background: var(--color-primary);
250}
251
252.cart-toast {
253    position: fixed;
254    right: 20px;
255    bottom: 20px;
256    z-index: 10;
257    padding: 12px 18px;
258    border-radius: 6px;
259    background: var(--color-dark-grey);
260    color: white;
261    opacity: 0;
262    pointer-events: none;
263    transform: translateY(10px);
264    transition: opacity .2s ease, transform .2s ease;
265}
266
267.cart-toast.is-visible {
268    opacity: 1;
269    transform: translateY(0);
270}
271
272@media (prefers-reduced-motion: reduce) {
273    #autoplay-progress-fill,
274    .cart-toast {
275        transition: none;
276    }
277}
278

JavaScript

javascript
1
2const objectArray = [
3    { name: 'Headphone', 
4    image: 'images/headphone.jpg', originalPrice: '2000',
5         price: '1299' },
6    { name: 'shoes',
7         image:'images/shoes2.webp', originalPrice: '1999',
8          price: '1399' },
9    { name: 'Necklace', image:'images/necklaace.webp', originalPrice: '50000', price: '28999' },
10    { name: 'badminton', image: 'images/badminton.webp',
11         originalPrice: '1599', price: '899' },
12    { name: 'water bottle', image: 'images/water bottle.webp',
13         originalPrice: '600', price: '499' },
14    { name: 'cushions', 
15        image: 'images/cushions.webp', originalPrice: '799', 
16        price: '599' },
17    { name: 'keyboard', 
18        image: 'images/keyboard.webp', originalPrice: '5000',
19         price: '3999' },
20    { name: 'television', image: 'images/television.webp', originalPrice: '80000', price: '71000' }
21];
22
23// as requirement stored products in javascript arrayof objects.
24const slider = document.getElementById('slider');
25
26slider.innerHTML = objectArray.map(function (item) {
27    // this function calculated the discount percentage whihc is written over the each object
28    const discount = Math.round(
29        ((Number(item.originalPrice) - Number(item.price)) / Number(item.originalPrice)) * 100
30    );
31
32    return `
33        <div class="thumbnail">
34            <button class="wishlist-toggle" type="button" aria-pressed="false"
35                    aria-label="Add ${item.name} to wishlist">♥</button>
36            <img src="${item.image}" alt="${item.name}" loading="lazy" decoding="async">
37            <div class="product-details">
38                <h2>${item.name}</h2>
39                <p><span>${item.originalPrice}</span> ${item.price}</p>
40                <div class="discount-badge">${discount}% OFF</div>
41                <button class="add-to-cart" type="button">Add to Cart</button>
42            </div>
43        </div>
44    `;
45}).join('');
46
47// thsi function i created as cards to ge to know the width of the cards and gap in between them.
48const cards = document.getElementsByClassName('thumbnail');
49
50function getScrollStep() {
51    return cards[0].getBoundingClientRect().width + 10;
52}
53
54const nextBtn = document.getElementById('slide-right');
55const prevBtn = document.getElementById('slide-left');
56
57// this is to move the slider left or right whenever user clicks left or right arrow in there
58prevBtn.addEventListener('click', function () {
59    slider.scrollLeft -= getScrollStep();
60    restartAutoplayTimer();
61});
62
63nextBtn.addEventListener('click', function () {
64    slider.scrollLeft += getScrollStep();
65    restartAutoplayTimer();
66});
67
68// this to move slider left or right
69slider.addEventListener('keydown', function (event) {
70    if (event.key === 'ArrowRight') {
71        slider.scrollBy({
72            left: getScrollStep(),
73            behavior: 'smooth'
74        });
75
76        event.preventDefault();
77        restartAutoplayTimer();
78    } else if (event.key === 'ArrowLeft') {
79        slider.scrollBy({
80            left: -getScrollStep(),
81            behavior: 'smooth'
82        });
83
84        event.preventDefault();
85        restartAutoplayTimer();
86    }
87});
88
89// the slider moves automatically after every 3 seconds 
90function moveToNextCard() {
91    const maxScrollLeft = slider.scrollWidth - slider.clientWidth;
92
93    // this is for when there are no cards so it will return and keep slider not moving
94    if (maxScrollLeft <= 0 || cards.length === 0) {
95        return;
96    }
97
98    // thsi si responsible for moving slider to back to the startwhen it reaches the end
99    if (slider.scrollLeft >= maxScrollLeft - 1) {
100        slider.scrollTo({ left: 0, behavior: 'smooth' });
101    } else {
102        // thsi is to move sliderto next card
103        const cardStep = cards[0].offsetWidth + 10;
104        slider.scrollBy({ left: cardStep, behavior: 'smooth' });
105    }
106}
107
108const autoplayButton = document.getElementById('autoplay-toggle');
109const progressBar = document.querySelector('.autoplay-progress');
110const progressFill = document.getElementById('autoplay-progress-fill');
111const cartMessage = document.getElementById('cart-toast');
112
113const autoplayDelay = 3000;
114let timer = null;
115let timeRemaining = autoplayDelay;
116let timerStartTime = null;
117let cartMessageTimer = null;
118
119// this function for the progress bar
120function startAutoplay() {
121    if (timer === null) {
122        progressFill.style.transition = 'none';
123        progressFill.style.width = `${((autoplayDelay - timeRemaining) / autoplayDelay) * 100}%`;
124
125        void progressFill.offsetWidth;
126
127        progressFill.style.transition = `width ${timeRemaining}ms linear`;
128        progressFill.style.width = '100%';
129
130        progressBar.setAttribute('aria-valuenow', String(autoplayDelay - timeRemaining));
131
132        timerStartTime = Date.now();
133
134        timer = setTimeout(function () {
135            timer = null;
136            timeRemaining = autoplayDelay;
137
138            progressFill.style.transition = 'none';
139            progressFill.style.width = '0%';
140            progressBar.setAttribute('aria-valuenow', '0');
141
142            moveToNextCard();
143            startAutoplay();
144        }, timeRemaining);
145
146        autoplayButton.textContent = 'Pause';
147        autoplayButton.setAttribute('aria-label', 'Pause automatic sliding');
148    }
149}
150
151// this function is for pausing the autoplay when user clicks the pause button at the bootm.
152function pauseAutoplay() {
153    if (timer !== null) {
154        clearTimeout(timer);
155
156        timeRemaining = Math.max(
157            0,
158            timeRemaining - (Date.now() - timerStartTime)
159        );
160
161        timer = null;
162        timerStartTime = null;
163
164        progressFill.style.transition = 'none';
165        progressFill.style.width = getComputedStyle(progressFill).width;
166    }
167
168    autoplayButton.textContent = 'Play';
169    autoplayButton.setAttribute('aria-label', 'Play automatic sliding');
170}
171
172// this makes sure the timer resatrt when user clcks any arrowor dot in carousel
173function restartAutoplayTimer() {
174    if (timer !== null) {
175        clearTimeout(timer);
176
177        timer = null;
178        timerStartTime = null;
179        timeRemaining = autoplayDelay;
180
181        progressFill.style.transition = 'none';
182        progressFill.style.width = '0%';
183        progressBar.setAttribute('aria-valuenow', '0');
184
185        startAutoplay();
186    }
187}
188//this is when user hovers through teh product it will pasue and the progress bar will start again when user leaver the mousefrom the product
189
190let wasAutoplayRunningBeforeHover = false;
191
192slider.addEventListener('mouseenter', function () {
193    wasAutoplayRunningBeforeHover = timer !== null;
194
195    if (wasAutoplayRunningBeforeHover) {
196        pauseAutoplay();
197    }
198});
199
200// Resume autoplay when the mouse leaves the carousel.
201slider.addEventListener('mouseleave', function () {
202    if (wasAutoplayRunningBeforeHover) {
203        startAutoplay();
204    }
205
206    wasAutoplayRunningBeforeHover = false;
207});
208
209// this function handles the clicks
210document.addEventListener('click', function (event) {
211    if (!(event.target instanceof Element)) {
212        return;
213    }
214
215    // this is to restart the autoplat bar timer once someone clicks the left or right arrow or dot
216    if (event.target.closest('.carousel-dot')) {
217        restartAutoplayTimer();
218    }
219
220    //this is to pop up the message add to cart
221    const addToCartButton = event.target.closest('.add-to-cart');
222
223    if (addToCartButton) {
224        const productName = addToCartButton
225            .closest('.thumbnail')
226            .querySelector('h2').textContent;
227
228        cartMessage.textContent = `${productName} added to cart`;
229        cartMessage.classList.add('is-visible');
230
231        clearTimeout(cartMessageTimer);
232
233        cartMessageTimer = setTimeout(function () {
234            cartMessage.classList.remove('is-visible');
235        }, 2500);
236    }
237
238    // Tthsi is wishlist toggle button .
239    const wishlistButton = event.target.closest('.wishlist-toggle');
240
241    if (wishlistButton) {
242        const isWishlisted = wishlistButton.getAttribute('aria-pressed') !== 'true';
243
244        const productName = wishlistButton
245            .closest('.thumbnail')
246            .querySelector('h2').textContent;
247
248        wishlistButton.setAttribute('aria-pressed', String(isWishlisted));
249
250        wishlistButton.setAttribute(
251            'aria-label',
252            `${isWishlisted ? 'Remove' : 'Add'} ${productName} ${isWishlisted ? 'from' : 'to'} wishlist`
253        );
254    }
255});
256
257// this is play pause button on the click.
258autoplayButton.addEventListener('click', function () {
259    if (timer === null) {
260        startAutoplay();
261    } else {
262        pauseAutoplay();
263    }
264});
265
266// this is start the autoplay automatically whenerver user loads the page
267startAutoplay();
268
269// Adjust the scroll position if the window size changes.
270window.addEventListener('resize', function () {
271    const maxScrollLeft = Math.max(
272        0,
273        slider.scrollWidth - slider.clientWidth
274    );
275
276    //this is to make sure slider does not get out of bound when windoes is resized
277
278    slider.scrollLeft = Math.min(
279        slider.scrollLeft,
280        maxScrollLeft
281    );
282});
283

Source Code

GitHub Repository: https://github.com/Sohamm-afk/auto-slider-javascript

Features

  • Dynamic product cards generated from a JavaScript array
  • Automatic carousel sliding
  • Previous and next navigation controls
  • Keyboard navigation
  • Discount percentage calculation
  • Wishlist toggle buttons
  • Add to Cart notifications
  • Autoplay pause and resume controls
  • Autoplay progress indicator
  • Responsive product display

Learning Outcomes

This project helped me practise DOM manipulation, JavaScript array methods, event handling, timer functions, dynamic HTML generation, and responsive web design.

Features

  • Responsive product cards with dynamic rendering

  • Automatic carousel sliding with play/pause controls

  • Previous/next navigation and pagination dots

  • Touch swipe and keyboard navigation

  • Add to Cart with live item count and total price

  • Shopping cart panel with quantity controls and item removal

  • Wishlist toggle with heart indicators

  • Discounted pricing and product ratings

  • Progress indicator for autoplay timing

  • Toast notifications for user actions

Built With

🎨

CSS3

⚡

JavaScript

🌐

HTML5

Compatibility

Browsers
SafariChromeFirefoxEdgeBrave
Devices
DesktopTabletMobile
Frameworks
Vanilla JSHTML/CSS

❓ FAQs

This component uses HTML5, CSS3, and vanilla JavaScript. It does not require a frontend framework or external libraries.

Yes. The layout adapts to different screen sizes and supports touch swipe navigation on compatible devices.

Yes. Users can add products, increase or decrease quantities, remove individual items, clear the cart, and view updated totals.

MetaSkillGroup

Written by

MetaSkillGroup

November 5, 2026

Guides from our blog

Need it built for you?

Built to the same standard as our client work.

If nothing here fits exactly, tell us what you need — our core developers build it. Requirements call first, a written SRS before any code, and a price agreed up front.