Horizontal scrolling galleries are everywhere right now, and it is easy to see why. They show off a lot of images in a small space, they feel great to swipe on a phone, and they stop your page from turning into an endless wall of pictures.
The question we see asked over and over in the Squarespace community is how to make one. The built-in gallery layouts are lovely, but a simple row that scrolls sideways is not one of them.
The good news? You can build one with a Code Block, and the heavy lifting is done by a CSS feature called scroll snap. Let’s dive in!
What we are building
- A single row of images that scrolls sideways with a swipe, a trackpad or the mouse wheel plus shift.
- Each image snaps neatly into place, so nothing ever stops half way between two cards.
- Two optional arrow buttons for visitors on desktop.
- Captions under every image.
- Keyboard friendly: you can tab to the gallery and use the arrow keys to move through it.
Step 1: Get your image links
This code uses regular image links rather than a Squarespace gallery block, so you need the web address of each picture. Here is an easy way to get them:
- Add your images to a page on your site (a hidden page that is not linked in your navigation works well).
- View that page on your live site, right-click each image and choose the option to copy the image address.
- Paste each address into a notepad so you have them ready.
Squarespace also has its own file storage for uploads, but where it lives changes between versions, so look for something called Files or Asset Library in your site settings if you prefer that route.
Step 2: Add the Code Block
- Click Edit on your page and add a Code block where you want the gallery.
- Turn Display Source off.
- Paste in the code below.
- Replace each
PASTE-IMAGE-URLwith one of your image addresses, and update the alt text and caption.
The code
<div class="sdl-gallery">
<div class="sdl-track" tabindex="0" role="region" aria-label="Project gallery">
<figure>
<img src="PASTE-IMAGE-URL-1" alt="Describe image 1">
<figcaption>Project one</figcaption>
</figure>
<figure>
<img src="PASTE-IMAGE-URL-2" alt="Describe image 2">
<figcaption>Project two</figcaption>
</figure>
<figure>
<img src="PASTE-IMAGE-URL-3" alt="Describe image 3">
<figcaption>Project three</figcaption>
</figure>
<figure>
<img src="PASTE-IMAGE-URL-4" alt="Describe image 4">
<figcaption>Project four</figcaption>
</figure>
<figure>
<img src="PASTE-IMAGE-URL-5" alt="Describe image 5">
<figcaption>Project five</figcaption>
</figure>
</div>
<div class="sdl-arrows">
<button type="button" class="sdl-prev" aria-label="Previous">←</button>
<button type="button" class="sdl-next" aria-label="Next">→</button>
</div>
</div>
<style>
.sdl-track { display: flex; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; padding-bottom: 16px; scrollbar-width: thin; }
.sdl-track figure { flex: 0 0 min(80%, 420px); margin: 0; scroll-snap-align: start; }
.sdl-track img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 12px; }
.sdl-track figcaption { margin-top: 8px; font-size: 0.9rem; }
.sdl-arrows { display: flex; gap: 8px; margin-top: 12px; }
.sdl-arrows button { width: 44px; height: 44px; border: 1px solid currentColor; border-radius: 50%; background: transparent; color: inherit; font-size: 1.2rem; cursor: pointer; }
@media (prefers-reduced-motion: no-preference) { .sdl-track { scroll-behavior: smooth; } }
</style>
<script>
(function () {
var track = document.querySelector('.sdl-track');
function slide(direction) {
var card = track.querySelector('figure');
var step = card.getBoundingClientRect().width + 16; // card width plus the gap
track.scrollBy({ left: direction * step });
}
document.querySelector('.sdl-prev').addEventListener('click', function () { slide(-1); });
document.querySelector('.sdl-next').addEventListener('click', function () { slide(1); });
})();
</script>
How it works (the short version)
The row is a flex container with overflow-x: auto, which is what makes it scroll sideways. Then scroll-snap-type: x mandatory tells the browser to always land exactly on a card, and scroll-snap-align: start on each card says which edge to line up. That is genuinely most of the magic.
The little script at the bottom only powers the arrow buttons. It measures the width of one card plus the gap, then scrolls by exactly that much.
Customizing your gallery
| You want | Change this |
|---|---|
| Bigger or smaller cards | The 420px in flex: 0 0 min(80%, 420px) |
| More space between cards | The gap: 16px on .sdl-track, and the + 16 in the script (keep them the same) |
| Square or wide images | The aspect-ratio: 4 / 3 value, for example 1 / 1 or 16 / 9 |
| Rounder corners | The border-radius: 12px on the images |
| No arrow buttons | Delete the sdl-arrows block and the script |
| More images | Copy a whole figure block and paste it below the last one |
Common problems
The images look squashed or stretched
That is the aspect ratio fighting your image shape. The object-fit: cover line crops images to fit, so if you want to see more of each picture, pick an aspect ratio closer to your originals.
It will not scroll sideways on desktop
Visitors with a plain mouse can use shift plus the wheel, drag the scrollbar, or use your arrow buttons. If you are not using the arrows, consider keeping them. They make a real difference on desktop.
The arrows do nothing
Check that you copied the script at the bottom and that Display Source is off. And remember that scripts only run on the live page, not inside the Squarespace editor.
The cards are too wide on mobile
The width is 80% of the screen on small devices, so you can always see a peek of the next card, which is a nice hint that there is more to swipe. If you want the peek smaller, change 80% to 88%.
Want something fancier?
If you are after the effect where a section pins in place and the content moves sideways as you scroll down the page, that is a different technique. Our Horizontal Scroll Sections plugin does exactly that, with a visual config generator. You can find it in the plugin collection.
Want more snippets like this one? Browse the Code Vault, our library of ready-to-paste Squarespace code, with one payment and lifetime access.
Why this post? It answers one of the questions Squarespace users ask most in the community forums. The code above is free to use and change, and every snippet was tested before we published it.



