Pure TailwindMIT licensed

Tailwind Infinite Logo Scroller Marquee with No JavaScript

A seamless, endlessly looping strip of partner logos — the 'trusted by' band on almost every SaaS landing page. The port's lesson: --animate-* in @theme mints animate-tcar03-scroll, so the animation becomes a design token like any colour.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tcar-03 w-full min-h-svh flex flex-col items-center justify-center gap-6 bg-tcar03-bg font-tcar03-sans py-10" aria-label="Trusted by leading teams">
  <p class="text-xs tracking-[0.16em] uppercase text-tcar03-mute m-0">Trusted by 4,000+ teams</p>
  <div class="group w-[min(720px,100%)] overflow-hidden [mask-image:linear-gradient(90deg,transparent,#000_12%,#000_88%,transparent)]">
    <ul class="list-none flex items-center gap-16 w-max m-0 p-0 animate-tcar03-scroll group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused] motion-reduce:animate-none motion-reduce:flex-wrap motion-reduce:justify-center motion-reduce:w-auto motion-reduce:gap-x-12 motion-reduce:gap-y-8">
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">NORTHWIND</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Lumen&amp;Co</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">ARCADIA</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">F&ouml;hn</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Kestrel</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">MONOLITH</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">NORTHWIND</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Lumen&amp;Co</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">ARCADIA</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">F&ouml;hn</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Kestrel</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">MONOLITH</li>
    </ul>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tcar03-bg: #f6f7f9;
  --color-tcar03-bg: oklch(0.97 0.003 255);
  --color-tcar03-mute: #8a93a3;
  --color-tcar03-mute: oklch(0.65 0.02 255);
  --color-tcar03-logo: #3e4654;
  --color-tcar03-logo: oklch(0.42 0.02 255);
  --font-tcar03-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tcar03-serif: 'Newsreader', Georgia, serif;
  --animate-tcar03-scroll: tcar03-scroll 24s linear infinite;
}
/* Keyframes have no utility form and never will. */

@keyframes tcar03-scroll {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(-50%);
  }
}

.tcar-03 {
  width: 100%;
  min-height: 100svh;
}

.tcar-03 ::selection {
  background: #111827;
  color: #fff;
}
/* Safari < 15.4 mask prefix. */

.tcar-03 .group {
  -webkit-mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tcar03-bg: #f6f7f9;
  --color-tcar03-bg: oklch(0.97 0.003 255);
  --color-tcar03-mute: #8a93a3;
  --color-tcar03-mute: oklch(0.65 0.02 255);
  --color-tcar03-logo: #3e4654;
  --color-tcar03-logo: oklch(0.42 0.02 255);
  --font-tcar03-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tcar03-serif: 'Newsreader', Georgia, serif;
  --animate-tcar03-scroll: tcar03-scroll 24s linear infinite;
}
/* Keyframes have no utility form and never will. */

@keyframes tcar03-scroll {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(-50%);
  }
}

.tcar-03 {
  width: 100%;
  min-height: 100svh;
}

.tcar-03 ::selection {
  background: #111827;
  color: #fff;
}
/* Safari < 15.4 mask prefix. */

.tcar-03 .group {
  -webkit-mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Newsreader:opsz,wght@6..72,500;6..72,700&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • --animate-tcar03-scroll in @theme is the whole reason this port is worth reading: an animation becomes a named design token with a generated utility, exactly like a colour.
  • animation-play-state is the one property here with no utility and no plausible future one — it is a state, not a scale. The arbitrary property on a group-hover: variant is idiomatic, not a workaround.
  • UI change from the CSS original: the reduced-motion fallback now sets an explicit gap-x-12 gap-y-8 wrapped grid rather than inheriting the 64px marquee gap, so the static version reads as a deliberate logo grid instead of a broken strip.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Infinite Logo Scroller Marquee with No JavaScript
Source: https://codefronts.com/snippets/tailwind-css-image-carousel/tailwind-infinite-logo-scroller-marquee-no-javascript/

A seamless, endlessly looping strip of partner logos — the 'trusted by' band on almost every SaaS landing page. The port's lesson: --animate-* in @theme mints animate-tcar03-scroll, so the animation becomes a design token like any colour.
## HTML
```html
<section class="tcar-03 w-full min-h-svh flex flex-col items-center justify-center gap-6 bg-tcar03-bg font-tcar03-sans py-10" aria-label="Trusted by leading teams">
  <p class="text-xs tracking-[0.16em] uppercase text-tcar03-mute m-0">Trusted by 4,000+ teams</p>
  <div class="group w-[min(720px,100%)] overflow-hidden [mask-image:linear-gradient(90deg,transparent,#000_12%,#000_88%,transparent)]">
    <ul class="list-none flex items-center gap-16 w-max m-0 p-0 animate-tcar03-scroll group-hover:[animation-play-state:paused] group-focus-within:[animation-play-state:paused] motion-reduce:animate-none motion-reduce:flex-wrap motion-reduce:justify-center motion-reduce:w-auto motion-reduce:gap-x-12 motion-reduce:gap-y-8">
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">NORTHWIND</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Lumen&amp;Co</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">ARCADIA</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">F&ouml;hn</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Kestrel</li>
      <li class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">MONOLITH</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">NORTHWIND</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Lumen&amp;Co</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">ARCADIA</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">F&ouml;hn</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">Kestrel</li>
      <li aria-hidden="true" class="flex-none text-[22px] font-bold tracking-[0.02em] text-tcar03-logo whitespace-nowrap font-tcar03-serif opacity-75">MONOLITH</li>
    </ul>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tcar03-bg: #f6f7f9;
  --color-tcar03-bg: oklch(0.97 0.003 255);
  --color-tcar03-mute: #8a93a3;
  --color-tcar03-mute: oklch(0.65 0.02 255);
  --color-tcar03-logo: #3e4654;
  --color-tcar03-logo: oklch(0.42 0.02 255);
  --font-tcar03-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tcar03-serif: 'Newsreader', Georgia, serif;
  --animate-tcar03-scroll: tcar03-scroll 24s linear infinite;
}
/* Keyframes have no utility form and never will. */

@keyframes tcar03-scroll {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(-50%);
  }
}

.tcar-03 {
  width: 100%;
  min-height: 100svh;
}

.tcar-03 ::selection {
  background: #111827;
  color: #fff;
}
/* Safari < 15.4 mask prefix. */

.tcar-03 .group {
  -webkit-mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
```

How this works

The animation is a token. Tailwind v4's --animate-* namespace turns an @theme entry into a utility, so the marquee reads animate-tcar03-scroll and the timing lives with the colours rather than in an anonymous rule at the bottom of the sheet. The @keyframes block itself stays CSS — there is no utility form for a keyframe, and there should not be.

The two-copy contract is markup, not style. The track holds the list twice; the keyframe ends at exactly -50%, so the reset is invisible. The duplicate half carries aria-hidden="true", so every logo is announced once.

Pause is a variant on the group. group-hover:[animation-play-state:paused] and its group-focus-within: twin let a user stop the strip to read a name — the same two states the CSS version wrote as a selector list.

Make it yours

  • Speed: the 24s in --animate-tcar03-scroll. Longer is slower.
  • Direction: add a second @theme entry ending in reverse, or flip the keyframe endpoints.
  • Fade width: the 12% / 88% stops in the mask.
  • Spacing: the track's gap-16.

Gotchas — read before shipping

  • Exactly two identical halves, and the keyframe must end at -50%. Three copies, or -100%, and the loop visibly jumps.
  • aria-hidden="true" on the duplicated set is not optional — without it a screen reader reads the whole client list twice.
  • animation-play-state has no utility; the arbitrary property is the answer, and it must sit on the animated element, not the hovered one — hence the group.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

CSS animation is universal and mask-image is Baseline since Safari 15.4; the floor quoted is Tailwind v4's generated sheet. The -webkit-mask shim is included for older Safari.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Arbitraryneeds bracket syntax

Plain CSSno Tailwind surface

Search CodeFronts

Loading…