I'm using the Slick carousel library to display reviews loaded dynamically from a review.json file. The setup works well, including autoplay and infinite scroll.
However, I want to restrict dragging (mouse or touch) so that users can only start dragging the slider from the center 50% area of the .review-scroll-wrapper (where the grab cursor is visually shown). Dragging from the left and right edges should be completely disabled.
CSS complete review section.
/*Reviews/Testimony Section*/.reviews-section { background-color: #0c1624; /* dark blue background */ color: white; padding: 120px 20px; /* text-align: right; min-height: 250px; */}.reviews-container { max-width: 1400px; margin: -200px auto 0 auto; /* top -20px, horizontal auto, bottom 0 */}.review-title { font-size: 45px; font-weight: bold; margin-bottom: 15px; text-align: center; font-family: 'Orbitron', sans-serif;}.review-title-gold { color: #Efc900; /* bright gold */}.review-scroll-wrapper { position: relative; overflow: hidden; cursor: grab; overflow-x: auto; scroll-behavior: smooth; scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* IE/Edge */ mask-image: linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%); -webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%); /* For Chrome, Safari */&::-webkit-scrollbar { display: none; }}/* .review-scroll-wrapper:active { cursor: grabbing;} *//* .card-holder { display: flex; gap: 30px; width: max-content; padding: 10px;} *//* Force Slick to respect your gap + card size */.slick-track { display: flex !important; gap: 30px !important; padding: 10px !important; margin-left: 0 !important; /* prevent centering */}.slick-slide { height: auto !important; display: flex !important; justify-content: center; /* optional */}/* Optional: if Slick wrapper centers */#scrollCards.slick-slider { text-align: left !important;}/* Optional: Hide flicker while Slick loads */#scrollCards { visibility: visible; opacity: 1;}.review-scroll-wrapper::before,.review-scroll-wrapper::after { content: ""; position: absolute; top: 0; width: 60px; height: 100%; z-index: 2; pointer-events: none;}.review-scroll-wrapper::before { left: 0; background: linear-gradient(to right, #0c1624, transparent);}.review-scroll-wrapper::after { right: 0; background: linear-gradient(to left, #0c1624, transparent);}.review-drag-zone { position: absolute; top: 0; left: 25%; width: 50%; height: 100%; z-index: 20; cursor: grab; pointer-events: auto;}.review-drag-zone:active { cursor: grabbing;}.review-scroll-wrapper .slick-track { cursor: default !important;}.review-card { flex: 0 0 auto; /* Prevent shrinking, enforce fixed width */ width: 320px; background-color: #0d191f; border: 1px solid #Efc900; border-radius: 20px; padding: 20px; box-sizing: border-box; display: flex; flex-direction: column; margin-top: 40px; color: white;}/* Main layout: pic, text, and icon */.review-header { display: flex; align-items: flex-start; position: relative;}/* Profile pic */.linkedin-pic { flex-shrink: 0;}.pic-prof { width: 50px; height: 50px; border-radius: 50%;}/* Name + role beside image */.review-info { margin-left: 15px;}/* LinkedIn icon on top right */.linkpic-url { position: absolute; top: 0; right: 0;}.linkedin-icon { width: 50px; height: 50px;}/* Name */.review-name { font-size: 18px; font-weight: bold; margin: 0; font-family: 'Times New Roman', sans-serif;}/* Role */.review-role { font-size: 12px; font-weight: bold; margin-top: 5px; color: #Efc900; font-family: 'Times New Roman', sans-serif;}/* Quote */.review-text { font-size: 16px; margin-top: 25px; color: #bbb; font-family: 'Times New Roman', serif;}JS
<script>fetch('review.json') .then(res => res.json()) .then(data => { const track = document.getElementById('scrollCards'); track.innerHTML = ''; data.forEach(review => { const card = document.createElement('div'); card.className = 'review-card'; card.innerHTML = `<div class="review-header"><div class="linkedin-pic"><img src="${review.image}" alt="${review.name}" class="pic-prof" /></div><div class="review-info"><h2 class="review-name">${review.name}</h2><h2 class="review-role">${review.role}</h2></div><div class="linkpic-url"><a href="${review.linkedin}" target="_blank" rel="noopener noreferrer"><img src="https://static.vecteezy.com/system/resources/previews/018/930/480/non_2x/linkedin-logo-linkedin-icon-transparent-free-png.png" alt="LinkedIn" class="linkedin-icon"/></a></div></div><h2 class="review-text">${review.text}</h2> `; const cardWrapper = document.createElement('div'); // <== Important! cardWrapper.appendChild(card); track.appendChild(cardWrapper); }); // ✅ Initialize Slick $('#scrollCards').slick({ infinite: true, slidesToShow: 1, variableWidth: true, slidesToScroll: 1, autoplay: true, autoplaySpeed: 5000, speed: 1000, arrows: false, dots: false, draggable: true, pauseOnHover: false, swipeToSlide: true, touchThreshold: 20, // 👇 resume autoplay after manual swipe responsive: [], // leave empty if not needed }).on('afterChange', function() { $(this).slick('slickPlay'); }); }) .catch(err => console.error('Review load failed:', err));</script><script>document.addEventListener('DOMContentLoaded', () => { const wrapper = document.querySelector('.review-scroll-wrapper'); const dragZone = document.querySelector('.review-drag-zone'); // Wait until Slick is initialized const interval = setInterval(() => { const slickTrack = document.querySelector('#scrollCards .slick-track'); if (!slickTrack) return; clearInterval(interval); // ✅ Once track exists, proceed // Always block dragging by default slickTrack.addEventListener('mousedown', (e) => { const bounds = dragZone.getBoundingClientRect(); const inside = e.clientX >= bounds.left && e.clientX <= bounds.right && e.clientY >= bounds.top && e.clientY <= bounds.bottom; if (!inside) { e.stopImmediatePropagation(); e.preventDefault(); } }); // Mobile drag block slickTrack.addEventListener('touchstart', (e) => { const bounds = dragZone.getBoundingClientRect(); const touch = e.touches[0]; const inside = touch.clientX >= bounds.left && touch.clientX <= bounds.right && touch.clientY >= bounds.top && touch.clientY <= bounds.bottom; if (!inside) { e.stopImmediatePropagation(); e.preventDefault(); } }); }, 50);});</script>HTML
<!--At the TOP Before body--><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script><script src="https://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script><section class="reviews-section"><div class="reviews-container"><h2 class="review-title"> Review of <span class="review-title-gold">our clients</span></h2><div class="review-scroll-wrapper"><!-- This is where Slick injects & scrolls --><div class="review-drag-zone"></div><div class="card-holder" id="scrollCards"></div><!-- This goes *on top* as a transparent overlay for drag limitation --></div></div></section>JSON
[ {"name": "Yoshi Tatsu","role": "Founder of YoshiT","image": "images/Yoshi.png","linkedin": "https://www.linkedin.com/in/reviewerlink/","text": "Very responsive and easy to work with. Got things done fast." }, {"name": "Isabella Moreno","role": "Marketing Lead at CoinLoop","image": "images/Isabella Moreno.png","linkedin": "https://www.linkedin.com/in/reviewerlink1/","text": "Professional and consistent. Would recommend." }, {"name": "Liam Chen","role": "CTO at BitNova","image": "images/Liam Chen.png","linkedin": "https://www.linkedin.com/in/reviewerlink2/","text": "Solid work. Helped us keep the community active and clean." }, {"name": "Ava Schmidt","role": "Community Manager at ChainSpark","image": "images/Ava Schmidt.png","linkedin": "https://www.linkedin.com/in/reviewerlink3/","text": "Fast, reliable, and detail-oriented." }, {"name": "Lucas Moreira","role": "Operations Lead at MetaEdge","image": "images/Lucas Moreira.png","linkedin": "https://www.linkedin.com/in/reviewerlink4/","text": "Communication was smooth. Always on point." }, {"name": "Sophia Nguyen","role": "Community Strategist at Web3Shift","image": "images/Sophia Nguyen.png","linkedin": "https://www.linkedin.com/in/reviewerlink5/","text": "Delivered exactly what we needed, no fluff." }]Current code example shows the cursor at correct area, however I cannot drag from the middle and in this example also blocks it from the left and right side..
I'm unable to make it work, whatever I tried I never managed to drag work only on center area (where grab cursor is seen), sometimes I was able to drag only from the left and right side but never the center... Is this possible with slider or do I have to look for different library? This library was recommended to me by a friend.
Core CSS<- (this should be related to the problem)
.review-drag-zone { position: absolute; top: 0; left: 25%; width: 50%; height: 100%; z-index: 20; cursor: grab; pointer-events: auto;}.review-drag-zone:active { cursor: grabbing;}.review-scroll-wrapper .slick-track { cursor: default !important;}