How to Add Inline Images to a Squarespace 7.1 Marquee Block (and Make Them Scroll Cleanly)

Dream it

〰️

img-1

〰️

Dream it 〰️ img-1 〰️

In this tutorial I'll show you how to add little images that scroll along inside a Squarespace Marquee block, so phrases like "Dream it · Build it · Ship it" can have a tiny photo travelling along with the text. The Marquee block by itself only handles text, so we'll add a small script and a couple of lines of CSS to bring the images in.

By the end of this guide you'll have a Marquee that:

  • Scrolls a repeating phrase across the page.

  • Replaces specific keywords like img-1 and img-2 with floating images that travel along with the text.

  • Cleanly disappears at the left and right edges, with no static images stuck to the side.

Take it one step at a time and you'll be done in about ten minutes.

What you're actually building

There are three moving parts. Knowing what each one does will make editing them later much less scary.

The first piece is the Marquee block itself. It's a standard Squarespace block you add from the block menu. You type your phrases into it, including special "keyword" words that you'll later replace with images. Squarespace handles the scrolling animation for you. The keywords are just placeholders, so on their own they will appear as plain text.

The second piece is a small JavaScript snippet in Code Injection. It watches the Marquee for those keywords, hides each keyword's text so it still takes up space but isn't visible, and then creates a floating image that follows the position of that hidden word on every animation frame. The result is an image that looks like it's embedded in the text and scrolling along with it.

The third piece is a few lines of Custom CSS that clip the Marquee at its edges. Without this, the floating images can spill out beyond the block's left and right boundaries, and orphan placeholder images can get stuck at the edges. The CSS keeps everything tidy.

Step 1. Build the Marquee block

Open your page in the Squarespace editor. Click the spot where you want the Marquee, then add a Marquee block from the block menu.

In the Marquee's settings, type your phrases into the items list. Anywhere you want an image to appear, type a placeholder keyword instead of an image. For example:

Dream it · img-1 · Build it · img-2 · Ship it · img-3

You can call the keywords anything you like (img-1, img-2, img-3 work nicely), as long as you pick words that don't appear anywhere else in the same Marquee text. Capitalisation doesn't matter.

Save the page so the block is committed.

Step 2. Find your section's data‑section‑id (the easy way)

The script needs to know which Marquee to work on. Every section on a Squarespace page has a unique data-section-id, and you'll paste yours into the script in the next step. The fastest way to find it is with a free Chrome extension called Squarespace ID Finder.

Install it from https://madebydave.org/squarespace-id and add it to Chrome. You don't need to leave the Squarespace editor to use it. Open the page that contains your Marquee in the editor, then click the extension's icon in your Chrome toolbar. It will overlay the section IDs directly on top of the editor preview.

Find the section that holds your Marquee, copy its ID, and keep it somewhere handy. The ID looks like a long string of letters and numbers, for example 6a13f66b0466a022dd3f3674.

Step 3. Add the Code Injection script

In Squarespace, go to Settings → Advanced → Code Injection. You'll see four boxes. The one you want is Footer. Paste the script below into the Footer box, then replace the placeholder bits with your own values.

There are three things you'll need to edit at the top of the script:

  1. The IMAGES map. Match your keywords to the image URLs you want.

  2. The SECTION_ID. Paste the id you copied a moment ago.

  3. The SIZE. Set the pixel size of each image.


Code to use

Add Code to Code Injection > Footer

<script>
/* =========================================================
   MARQUEE KEYWORD -> IMAGE REPLACER
   Replaces specific keywords in a Squarespace marquee block
   with floating SVG <image> nodes that follow the text path.
   ========================================================= */
(function () {

  /* ---------- EDIT HERE: keyword -> image URL map ---------- */
  /* Type the keyword exactly (case-insensitive) inside any   */
  /* marquee item to have it replaced by this image.          */
  var IMAGES = {
    'img-1': 'https://picsum.photos/id/1062/120/120',
    'img-2': 'https://picsum.photos/id/1025/120/120',
    'img-3': 'https://picsum.photos/id/237/120/120'
  };

  /* ---------- EDIT HERE: which section to target ----------- */
  /* Right-click the marquee section in the live page and     */
  /* copy its data-section-id attribute.                      */
  var SEL = 'section[data-section-id="6a13f66b0466a022dd3f3674"]';

  /* ---------- EDIT HERE: image size in px ------------------ */
  var SIZE = 50;

  /* ---------- internals (no need to edit below) ------------ */
  var SVGNS  = 'http://www.w3.org/2000/svg';
  var XLINK  = 'http://www.w3.org/1999/xlink';
  var section, bindings = [], raf = null;

  // Find every keyword tspan in the marquee and attach an <image> to it.
  function build() {
    section = document.querySelector(SEL);
    if (!section) return false;
    bindings = [];
    section.querySelectorAll('.Marquee-svg-text').forEach(function (tp) {
      var textEl = tp.closest('text');
      var svg    = textEl && textEl.closest('svg');
      var offset = 0;
      tp.querySelectorAll('tspan').forEach(function (t) {
        var raw = (t.textContent || '').trim().toLowerCase();
        var len = (t.textContent || '').length;
        if (IMAGES[raw] && svg) {
          // hide the keyword text but keep its width so layout is unaffected
          t.setAttribute('fill', 'transparent');
          t.style.fill = 'transparent';
          // create the floating <image>
          var img = document.createElementNS(SVGNS, 'image');
          img.setAttributeNS(XLINK, 'href', IMAGES[raw]);
          img.setAttribute('href',   IMAGES[raw]);
          img.setAttribute('width',  SIZE);
          img.setAttribute('height', SIZE);
          img.setAttribute('class',  'marquee-img');
          img.setAttribute('x', -9999);
          img.setAttribute('y', -9999);
          svg.appendChild(img);
          bindings.push({ image: img, textEl: textEl, idx: offset, len: len });
        }
        offset += len;
      });
    });
    return bindings.length > 0;
  }

  // Each frame: move each <image> to the centre of its hidden keyword.
  function tick() {
    bindings.forEach(function (b) {
      try {
        var total = (b.textEl.textContent || '').length;
        if (b.idx >= total) return;
        var s = b.textEl.getStartPositionOfChar(b.idx);
        var e = b.textEl.getEndPositionOfChar(Math.min(b.idx + b.len - 1, total - 1));
        b.image.setAttribute('x', (s.x + e.x) / 2 - SIZE / 2);
        b.image.setAttribute('y', (s.y + e.y) / 2 - SIZE / 2);
      } catch (_) { /* layout not ready yet */ }
    });
    raf = requestAnimationFrame(tick);
  }

  function start() { if (raf == null) raf = requestAnimationFrame(tick); }
  function stop()  { if (raf != null) { cancelAnimationFrame(raf); raf = null; } }

  function init() {
    // marquee may render late — keep trying until the section exists
    if (!build()) return setTimeout(init, 500);
    start();
    // re-bind if the marquee re-renders its tspans
    new MutationObserver(function (muts) {
      var rebind = muts.some(function (m) {
        return Array.from(m.addedNodes).some(function (n) {
          return n.nodeType === 1 &&
                 n.matches &&
                 (n.matches('tspan') || (n.querySelector && n.querySelector('tspan')));
        });
      });
      if (rebind) {
        stop();
        section.querySelectorAll('image.marquee-img').forEach(function (i) { i.remove(); });
        build();
        start();
      }
    }).observe(section, { childList: true, subtree: true });
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
</script>script></script>

The full script body (the build(), tick(), init() and MutationObserver parts) sits below the comment "internals". Don't touch those unless you want to change how the image positions are calculated.

Click Save in the top‑left.

To swap one of the images for a different photo later, just change its URL in the IMAGES map and save. To add another keyword and image pair, add a new line in the IMAGES block. Don't forget the comma after the previous line. The keywords in your Marquee text and the keys in this map must match exactly, but capitalisation doesn't matter.

Step 4. Add the Custom CSS

The script can sometimes leave a floating image positioned right at the edge of the Marquee, where it sits and doesn't scroll. Two short CSS rules fix this completely.

Go to Website → Custom CSS in the side panel of the Squarespace editor, and paste this in:

/* keyword image swap supporting styles */
section[data-section-id='6a13f66b0466a022dd3f3674'] .Marquee-svg-text image.marquee-img { overflow: visible; }

/* Hard-clip the marquee so items completely disappear at the block edges.
   The Squarespace Marquee block's inline <svg> has style="overflow:visible",
   so we must use !important and target .Marquee-svg directly to override it. */
.sqs-block-marquee,
.sqs-block-marquee .Marquee,
.sqs-block-marquee .Marquee-display,
.sqs-block-marquee .Marquee-svg {
  overflow: hidden !important;
}

/* Also clip any <image> items that escape the SVG paint box (belt-and-braces). */
.sqs-block-marquee .Marquee-display {
  clip-path: inset(0) !important;
}

/* Hide the static placeholder marquee images Squarespace renders at x="-25" y="-25".
   These never animate and were causing a static image stuck to the left edge. */
.sqs-block-marquee .Marquee-svg image.marquee-img[x="-25"][y="-25"] {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
}

Here's what these two rules do.

The first rule clips anything that tries to paint outside the Marquee's box. The !important part really matters, because the Marquee's inner SVG has an inline style="overflow: visible" that would otherwise win the CSS battle.

The second rule hides a small quirk of the keyword image script. When a keyword is briefly off‑screen, the script can't compute its position, so it parks the corresponding image at coordinates (-25, -25). That puts your image right at the left edge of the block, looking like it's stuck there. Hiding any <image> with those exact coordinates makes the problem disappear.

Save the Custom CSS and check the live preview. The Marquee should now scroll smoothly with your images travelling along with the text, and there should be nothing static at the edges.

Editing it later

When you want to change what shows up, here's where to go.

  • New phrase or new keyword? Edit the Marquee block on the page.

  • Different image? Change the URL in the IMAGES map in Code Injection.

  • Bigger or smaller image? Change the SIZE value in the script.

  • Moving the Marquee to a different section? Open that page in the editor, click the Squarespace ID Finder extension to reveal the new section's ID, copy it, and replace the value of SECTION_ID in the script.

If you ever delete the Marquee or move it to a new page, remember to update the SECTION_ID. Otherwise the script will look for a section that no longer exists and quietly do nothing.

Troubleshooting

If the images don't appear at all, the most likely cause is a mismatched SECTION_ID or a broken image URL. Open the page in the Squarespace editor, run the Squarespace ID Finder extension again to confirm the ID matches what's in your script, then check each image URL by pasting it into a new browser tab to make sure it actually loads.

If you see your keywords as plain text instead of images, the script isn't running yet. Confirm you pasted it into the Footer Code Injection box (not the Header), and that it's wrapped in <script> tags.

If an image appears stuck at the left edge of the Marquee and never moves, the placeholder‑hiding CSS rule isn't applied. Re‑check your Custom CSS, make sure the second block above is present, and make sure you saved.

If images bleed past the right or left edge of the block, the overflow CSS rule isn't applied. Check that all four selectors are there and that !important is on the overflow line.

That's the whole thing. Once it's set up, day‑to‑day editing is just typing new phrases into the Marquee block or swapping image URLs in the script. Have fun with it.

Dave Hawkins

As a top tier Squarespace Expert and founder of Made by Dave, I bring over 10 years of Squarespace experience and 600+ bespoke website launches. Our process combines consultancy, design, project management and development for a collaborative and efficient experience with clients like you. Whether you need a new website or updates for your existing site, we'll help you get up and running.

https://madebydave.org
Next
Next

Two Days at BrightonSEO Spring 2026: A Squarespace Designer on the Stand