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
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 structurestyle.css— Styling and responsive layoutscript.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
html1<!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
css1@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
javascript1 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
❓ 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.

Written by
MetaSkillGroup
Guides from our blog
Frontend Developer Roadmap 2026: A Step-by-Step Guide for BeginnersA simple, step-by-step frontend developer roadmap for 2026. Learn HTML, CSS, JavaScript, Git, React, TypeScript and Next.js in the right order, with a 6-month study plan, beginner projects, free resources and a checklist for your first frontend internship.
MERN Stack Roadmap for Beginners 2026: A Step-by-Step Guide to Becoming a Full-Stack DeveloperConfused about where to start with MERN? This step-by-step MERN stack roadmap for 2026 takes you from zero to your first full-stack project. Learn JavaScript, Node.js, Express, MongoDB and React in the right order, with a clear timeline, milestone projects, common mistakes and tips to learn faster with AI tools.
Top 7 React Optimization Techniques to Boost Your App Performance in 2026.Learn the top 7 React optimization techniques including Lazy Loading, Memoization, Debouncing, Throttling, Virtualization, Code Splitting, and Caching to build blazing fast React apps in 2026.
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.