Description
- enable support: trackpad, keyboard, drag to scroll on Reel gallery
- view demo – password: abc
- buy me a coffee

#1. Install Code
#1.1. Hover on Page where you use Reel Gallery > Click Gear icon

#1.2. Click Advanced > Paste this code
- If you use Personal/Basic Plan and your plan doesn’t support Injection, see #3.1
<!-- 07.26c31v2 Reel Trackpad -->
<script>
window.ReelTrackpadConfig = {
reelSelector: '.gallery-reel[data-controller="GalleryReel"]',
enableWheel: true,
wheelIncludeVertical: true,
wheelThreshold: 40,
wheelCooldown: 350,
enableDrag: true,
dragIncludeTouch: false,
dragThreshold: 45,
dragStepDistance: 220,
enableKeyboard: true,
keyboardScope: 'hover'
};
</script>
<script>
(function () {
'use strict';
var cfg = window.ReelTrackpadConfig;
if (!cfg) return;
var MOVE_TOLERANCE = 5;
var STYLE_ID = 'reel-tp-style';
function injectStyle() {
if (document.getElementById(STYLE_ID)) return;
var s = document.createElement('style');
s.id = STYLE_ID;
s.textContent =
'.reel-tp-grab{cursor:grab}' +
'.reel-tp-grab.reel-tp-dragging{cursor:grabbing;user-select:none}' +
'.reel-tp-grab.reel-tp-dragging img{pointer-events:none}';
document.head.appendChild(s);
}
function step(reel, dir) {
var sel = dir > 0 ? '[data-next]' : '[data-previous]';
var btn = reel.querySelector('.gallery-reel-controls ' + sel);
if (btn) btn.click();
}
function isTyping() {
var el = document.activeElement;
if (!el) return false;
var tag = el.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
}
function handleKey(reel, e) {
if (isTyping()) return;
if (e.key === 'ArrowRight') { step(reel, 1); e.preventDefault(); }
else if (e.key === 'ArrowLeft') { step(reel, -1); e.preventDefault(); }
}
function bindWheel(reel) {
var accum = 0, locked = false, timer;
function release() { locked = false; accum = 0; }
reel.addEventListener('wheel', function (e) {
var horizontal = Math.abs(e.deltaX) >= Math.abs(e.deltaY);
var delta = horizontal ? e.deltaX : (cfg.wheelIncludeVertical ? e.deltaY : 0);
if (!delta) return;
e.preventDefault();
clearTimeout(timer);
timer = setTimeout(release, cfg.wheelCooldown);
if (locked) return;
accum += delta;
if (Math.abs(accum) >= cfg.wheelThreshold) {
step(reel, accum > 0 ? 1 : -1);
accum = 0;
locked = true;
}
}, { passive: false });
}
function bindDrag(reel) {
var list = reel.querySelector('.gallery-reel-list') || reel;
var dragging = false, moved = false, startX = 0, pid = null;
list.classList.add('reel-tp-grab');
list.addEventListener('pointerdown', function (e) {
if (!cfg.dragIncludeTouch && e.pointerType === 'touch') return;
if (e.button !== undefined && e.button !== 0) return;
dragging = true; moved = false; startX = e.clientX; pid = e.pointerId;
});
list.addEventListener('pointermove', function (e) {
if (!dragging) return;
var dist = e.clientX - startX;
if (!moved && Math.abs(dist) > MOVE_TOLERANCE) {
moved = true;
list.classList.add('reel-tp-dragging');
if (list.setPointerCapture && pid != null) {
try { list.setPointerCapture(pid); } catch (err) {}
}
}
if (moved) e.preventDefault();
});
function endDrag(e) {
if (!dragging) return;
dragging = false;
list.classList.remove('reel-tp-dragging');
var dist = e.clientX - startX;
if (!moved || Math.abs(dist) < cfg.dragThreshold) return;
var dir = dist < 0 ? 1 : -1;
var steps = cfg.dragStepDistance > 0
? Math.max(1, Math.round(Math.abs(dist) / cfg.dragStepDistance))
: 1;
for (var i = 0; i < steps; i++) step(reel, dir);
}
list.addEventListener('pointerup', endDrag);
list.addEventListener('pointercancel', function () {
dragging = false;
list.classList.remove('reel-tp-dragging');
});
list.addEventListener('click', function (e) {
if (moved) { e.preventDefault(); e.stopPropagation(); moved = false; }
}, true);
list.addEventListener('dragstart', function (e) {
if (dragging) e.preventDefault();
});
}
function bindKeyboard(reel) {
if (cfg.keyboardScope === 'focus') {
if (!reel.hasAttribute('tabindex')) reel.setAttribute('tabindex', '0');
reel.addEventListener('keydown', function (e) { handleKey(reel, e); });
return;
}
if (cfg.keyboardScope === 'hover') {
var over = false;
reel.addEventListener('pointerenter', function () { over = true; });
reel.addEventListener('pointerleave', function () { over = false; });
document.addEventListener('keydown', function (e) { if (over) handleKey(reel, e); });
return;
}
var inView = false;
if ('IntersectionObserver' in window) {
new IntersectionObserver(function (entries) {
entries.forEach(function (en) { inView = en.isIntersecting; });
}, { threshold: 0.3 }).observe(reel);
} else {
inView = true;
}
document.addEventListener('keydown', function (e) { if (inView) handleKey(reel, e); });
}
function initReel(reel) {
if (reel.dataset.reelTrackpadDone) return;
var next = reel.querySelector('.gallery-reel-controls [data-next]');
var prev = reel.querySelector('.gallery-reel-controls [data-previous]');
if (!next && !prev) return;
reel.dataset.reelTrackpadDone = '1';
if (cfg.enableWheel) bindWheel(reel);
if (cfg.enableDrag) { injectStyle(); bindDrag(reel); }
if (cfg.enableKeyboard) bindKeyboard(reel);
}
function run() {
if (document.body.classList.contains('sqs-edit-mode-active')) return;
document.querySelectorAll(cfg.reelSelector).forEach(initReel);
}
window.addEventListener('load', run);
window.addEventListener('mercury:load', run);
})();
</script>

#2. Customize
nothing now
#3. Other
#3.1. If you use Personal/Basic Plan and your plan doesn’t support Injection, you can edit current page (page where you use Slideshow Reel) > Add a Block > Choose Markdown
![]()
Add this code into Markdown
<script>
window.ReelTrackpadConfig = {
reelSelector: '.gallery-reel[data-controller="GalleryReel"]',
enableWheel: true,
wheelIncludeVertical: true,
wheelThreshold: 40,
wheelCooldown: 350,
enableDrag: true,
dragIncludeTouch: false,
dragThreshold: 45,
dragStepDistance: 220,
enableKeyboard: true,
keyboardScope: 'hover'
};
</script>
<script>
(function () {
'use strict';
var cfg = window.ReelTrackpadConfig;
if (!cfg) return;
var MOVE_TOLERANCE = 5;
var STYLE_ID = 'reel-tp-style';
function injectStyle() {
if (document.getElementById(STYLE_ID)) return;
var s = document.createElement('style');
s.id = STYLE_ID;
s.textContent =
'.reel-tp-grab{cursor:grab}' +
'.reel-tp-grab.reel-tp-dragging{cursor:grabbing;user-select:none}' +
'.reel-tp-grab.reel-tp-dragging img{pointer-events:none}';
document.head.appendChild(s);
}
function step(reel, dir) {
var sel = dir > 0 ? '[data-next]' : '[data-previous]';
var btn = reel.querySelector('.gallery-reel-controls ' + sel);
if (btn) btn.click();
}
function isTyping() {
var el = document.activeElement;
if (!el) return false;
var tag = el.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
}
function handleKey(reel, e) {
if (isTyping()) return;
if (e.key === 'ArrowRight') { step(reel, 1); e.preventDefault(); }
else if (e.key === 'ArrowLeft') { step(reel, -1); e.preventDefault(); }
}
function bindWheel(reel) {
var accum = 0, locked = false, timer;
function release() { locked = false; accum = 0; }
reel.addEventListener('wheel', function (e) {
var horizontal = Math.abs(e.deltaX) >= Math.abs(e.deltaY);
var delta = horizontal ? e.deltaX : (cfg.wheelIncludeVertical ? e.deltaY : 0);
if (!delta) return;
e.preventDefault();
clearTimeout(timer);
timer = setTimeout(release, cfg.wheelCooldown);
if (locked) return;
accum += delta;
if (Math.abs(accum) >= cfg.wheelThreshold) {
step(reel, accum > 0 ? 1 : -1);
accum = 0;
locked = true;
}
}, { passive: false });
}
function bindDrag(reel) {
var list = reel.querySelector('.gallery-reel-list') || reel;
var dragging = false, moved = false, startX = 0, pid = null;
list.classList.add('reel-tp-grab');
list.addEventListener('pointerdown', function (e) {
if (!cfg.dragIncludeTouch && e.pointerType === 'touch') return;
if (e.button !== undefined && e.button !== 0) return;
dragging = true; moved = false; startX = e.clientX; pid = e.pointerId;
});
list.addEventListener('pointermove', function (e) {
if (!dragging) return;
var dist = e.clientX - startX;
if (!moved && Math.abs(dist) > MOVE_TOLERANCE) {
moved = true;
list.classList.add('reel-tp-dragging');
if (list.setPointerCapture && pid != null) {
try { list.setPointerCapture(pid); } catch (err) {}
}
}
if (moved) e.preventDefault();
});
function endDrag(e) {
if (!dragging) return;
dragging = false;
list.classList.remove('reel-tp-dragging');
var dist = e.clientX - startX;
if (!moved || Math.abs(dist) < cfg.dragThreshold) return;
var dir = dist < 0 ? 1 : -1;
var steps = cfg.dragStepDistance > 0
? Math.max(1, Math.round(Math.abs(dist) / cfg.dragStepDistance))
: 1;
for (var i = 0; i < steps; i++) step(reel, dir);
}
list.addEventListener('pointerup', endDrag);
list.addEventListener('pointercancel', function () {
dragging = false;
list.classList.remove('reel-tp-dragging');
});
list.addEventListener('click', function (e) {
if (moved) { e.preventDefault(); e.stopPropagation(); moved = false; }
}, true);
list.addEventListener('dragstart', function (e) {
if (dragging) e.preventDefault();
});
}
function bindKeyboard(reel) {
if (cfg.keyboardScope === 'focus') {
if (!reel.hasAttribute('tabindex')) reel.setAttribute('tabindex', '0');
reel.addEventListener('keydown', function (e) { handleKey(reel, e); });
return;
}
if (cfg.keyboardScope === 'hover') {
var over = false;
reel.addEventListener('pointerenter', function () { over = true; });
reel.addEventListener('pointerleave', function () { over = false; });
document.addEventListener('keydown', function (e) { if (over) handleKey(reel, e); });
return;
}
var inView = false;
if ('IntersectionObserver' in window) {
new IntersectionObserver(function (entries) {
entries.forEach(function (en) { inView = en.isIntersecting; });
}, { threshold: 0.3 }).observe(reel);
} else {
inView = true;
}
document.addEventListener('keydown', function (e) { if (inView) handleKey(reel, e); });
}
function initReel(reel) {
if (reel.dataset.reelTrackpadDone) return;
var next = reel.querySelector('.gallery-reel-controls [data-next]');
var prev = reel.querySelector('.gallery-reel-controls [data-previous]');
if (!next && !prev) return;
reel.dataset.reelTrackpadDone = '1';
if (cfg.enableWheel) bindWheel(reel);
if (cfg.enableDrag) { injectStyle(); bindDrag(reel); }
if (cfg.enableKeyboard) bindKeyboard(reel);
}
function run() {
if (document.body.classList.contains('sqs-edit-mode-active')) return;
document.querySelectorAll(cfg.reelSelector).forEach(initReel);
}
window.addEventListener('load', run);
window.addEventListener('mercury:load', run);
})();
</script>
