Oblivion
Oblivion
Docs
Go back
Component by
OV
Oblivion
Google
NETFLIX
Microsoft
Spotify
Google
NETFLIX
Microsoft
Spotify
Google
NETFLIX
Microsoft
Spotify
Google
NETFLIX
Microsoft
Spotify
TSX
infinite-marquee
"use client"

import React from "react"

export const componentMeta = {
  name: "Infinite Marquee",
  description: "A seamless infinite scrolling bar with multiple rows, reverse directions, and authentic SVGs.",
  props: {}
}

const logosRow1 = [
  { name: "Google", className: "font-sans font-medium tracking-tighter text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" /></svg> },
  { name: "NETFLIX", className: "font-black tracking-widest text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="m5.398 0 8.348 23.602c2.346.059 4.856.398 4.856.398L10.113 0H5.398zm8.489 0v9.172l4.715 13.33V0h-4.715zM5.398 1.5V24c1.873-.225 2.81-.312 4.715-.398V14.83L5.398 1.5z" /></svg> },
  { name: "Microsoft", className: "font-semibold tracking-tight text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M2 2h9v9H2zm11 0h9v9h-9zM2 13h9v9H2zm11 0h9v9h-9z" /></svg> },
  { name: "Spotify", className: "font-bold tracking-tight text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z" /></svg> }
]

const logosRow2 = [
  { name: "Vercel", className: "font-bold tracking-tight text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="m12 1.608 12 20.784H0Z" /></svg> },
  { name: "zomato", className: "font-black italic tracking-tighter text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M19.615 9.45l-1.258.473-.167.71-.446.021-.115.978h.408l-.211 1.51c-.131.939.036 1.381.865 1.381.488 0 .91-.175 1.135-.297l.145-.9c-.167.083-.436.19-.618.19-.247 0-.276-.13-.225-.488l.189-1.396h.843c.03-.206.131-.877.16-1h-.865zm-3.779 1.002c-.115.002-.236.01-.361.026a3.592 3.592 0 0 0-1.347.432l.26.789c.269-.15.615-.28.978-.326.538-.066.757.1.79.375.014.109.004.199-.005.289l-.014.056a3.46 3.46 0 0 0-1.097-.036c-.518.063-.943.273-1.204.6a1.324 1.324 0 0 0-.225 1.034c.127.583.553.84 1.199.76.45-.055.812-.27 1.076-.63a2.665 2.665 0 0 1-.03.304 1.74 1.74 0 0 1-.072.29l1.244.001a3.657 3.657 0 0 1-.001-.365c.036-.459.118-1.143.247-2.051a2.397 2.397 0 0 0-.002-.59c-.08-.644-.628-.969-1.436-.958zm6.536.063c-1.194 0-2.107 1.067-2.107 2.342 0 .959.552 1.693 1.628 1.693 1.2 0 2.107-1.067 2.107-2.35 0-.95-.538-1.685-1.628-1.685zm-11.777.041c-.538 0-1.12.465-1.52 1.236.102-.504.08-1.076.051-1.198a8.964 8.964 0 0 1-1.287.122 6.9 6.9 0 0 1-.073 1.243l-.167 1.145c-.066.45-.138.969-.211 1.297h1.353c.007-.199.058-.511.094-.786l.116-.786c.095-.511.502-1.114.815-1.114.182 0 .175.176.124.504l-.131.885c-.066.45-.138.969-.211 1.297h1.367c.008-.199.051-.512.088-.786l.116-.786c.094-.512.502-1.114.814-1.114.182 0 .175.168.146.396l-.327 2.29H13l.438-2.609c.095-.649.044-1.236-.676-1.236-.523 0-1.09.443-1.49 1.182.087-.61.036-1.182-.677-1.182zm-4.88.008c-1.177 0-2.08 1.053-2.08 2.312 0 .946.546 1.67 1.608 1.67 1.185 0 2.08-1.052 2.08-2.319 0-.938-.531-1.663-1.607-1.663zm-5.126.091c-.05.39-.102.778-.175 1.13.328-.008.619-.016 1.411-.016l-1.81 1.96-.015.703c.444-.03.997-.039 1.63-.039.566 0 1.134.008 1.497.039.065-.458.13-.763.21-1.137-.275.015-.755.023-1.512.023l1.81-1.969.023-.694c-.437.023-.83.03-1.52.03-.749 0-.975-.007-1.549-.03zm4.988.927c.255 0 .408.228.408.701 0 .687-.276 1.251-.626 1.251-.261 0-.414-.236-.414-.702 0-.694.283-1.25.632-1.25zm16.629 0c.254 0 .407.228.407.701 0 .687-.276 1.251-.625 1.251-.262 0-.415-.236-.415-.702 0-.694.284-1.25.633-1.25zM15.51 12.64c.206-.003.403.024.55.058l-.013.118c-.075.44-.39.881-.848.938-.31.037-.578-.148-.608-.39a.538.538 0 0 1 .114-.41c.117-.159.336-.268.599-.3.069-.009.138-.013.206-.014Z" /></svg> },
  { name: "Uber", className: "font-normal tracking-wide text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M0 7.97v4.958c0 1.867 1.302 3.101 3 3.101.826 0 1.562-.316 2.094-.87v.736H6.27V7.97H5.082v4.888c0 1.257-.85 2.106-1.947 2.106-1.11 0-1.946-.827-1.946-2.106V7.971H0zm7.44 0v7.925h1.13v-.725c.521.532 1.257.86 2.06.86a3.006 3.006 0 0 0 3.034-3.01 3.01 3.01 0 0 0-3.033-3.024 2.86 2.86 0 0 0-2.049.861V7.971H7.439zm9.869 2.038c-1.687 0-2.965 1.37-2.965 3 0 1.72 1.334 3.01 3.066 3.01 1.053 0 1.913-.463 2.49-1.233l-.826-.611c-.43.577-.996.847-1.664.847-.973 0-1.753-.7-1.912-1.64h4.697v-.373c0-1.72-1.222-3-2.886-3zm6.295.068c-.634 0-1.098.294-1.381.758v-.713h-1.131v5.774h1.142V12.61c0-.894.544-1.47 1.291-1.47H24v-1.065h-.396zm-6.319.928c.85 0 1.564.588 1.756 1.47H15.52c.203-.882.916-1.47 1.765-1.47zm-6.732.012c1.086 0 1.98.883 1.98 2.004a1.993 1.993 0 0 1-1.98 2.001A1.989 1.989 0 0 1 8.56 13.02a1.99 1.99 0 0 1 1.992-2.004z" /></svg> },
  { name: "stripe", className: "font-bold tracking-tighter text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M13.976 9.15c-2.172-.806-3.356-1.426-3.356-2.409 0-.831.683-1.305 1.901-1.305 2.227 0 4.515.858 6.09 1.631l.89-5.494C18.252.975 15.697 0 12.165 0 9.667 0 7.589.654 6.104 1.872 4.56 3.147 3.757 4.992 3.757 7.218c0 4.039 2.467 5.76 6.476 7.219 2.585.92 3.445 1.574 3.445 2.583 0 .98-.84 1.545-2.354 1.545-1.875 0-4.965-.921-6.99-2.109l-.9 5.555C5.175 22.99 8.385 24 11.714 24c2.641 0 4.843-.624 6.328-1.813 1.664-1.305 2.525-3.236 2.525-5.732 0-4.128-2.524-5.851-6.594-7.305h.003z" /></svg> },
  { name: "airbnb", className: "font-bold tracking-tighter text-3xl md:text-4xl", icon: <svg viewBox="0 0 24 24" className="w-8 h-8 mr-3 fill-current"><path d="M12.001 18.275c-1.353-1.697-2.148-3.184-2.413-4.457-.263-1.027-.16-1.848.291-2.465.477-.71 1.188-1.056 2.121-1.056s1.643.345 2.12 1.063c.446.61.558 1.432.286 2.465-.291 1.298-1.085 2.785-2.412 4.458zm9.601 1.14c-.185 1.246-1.034 2.28-2.2 2.783-2.253.98-4.483-.583-6.392-2.704 3.157-3.951 3.74-7.028 2.385-9.018-.795-1.14-1.933-1.695-3.394-1.695-2.944 0-4.563 2.49-3.927 5.382.37 1.565 1.352 3.343 2.917 5.332-.98 1.085-1.91 1.856-2.732 2.333-.636.344-1.245.558-1.828.609-2.679.399-4.778-2.2-3.825-4.88.132-.345.395-.98.845-1.961l.025-.053c1.464-3.178 3.242-6.79 5.285-10.795l.053-.132.58-1.116c.45-.822.635-1.19 1.351-1.643.346-.21.77-.315 1.246-.315.954 0 1.698.558 2.016 1.007.158.239.345.557.582.953l.558 1.089.08.159c2.041 4.004 3.821 7.608 5.279 10.794l.026.025.533 1.22.318.764c.243.613.294 1.222.213 1.858zm1.22-2.39c-.186-.583-.505-1.271-.9-2.094v-.03c-1.889-4.006-3.642-7.608-5.307-10.844l-.111-.163C15.317 1.461 14.468 0 12.001 0c-2.44 0-3.476 1.695-4.535 3.898l-.081.16c-1.669 3.236-3.421 6.843-5.303 10.847v.053l-.559 1.22c-.21.504-.317.768-.345.847C-.172 20.74 2.611 24 5.98 24c.027 0 .132 0 .265-.027h.372c1.75-.213 3.554-1.325 5.384-3.317 1.829 1.989 3.635 3.104 5.382 3.317h.372c.133.027.239.027.265.027 3.37.003 6.152-3.261 4.802-6.975z" /></svg> }
]

export default function InfiniteMarquee() {
  return (
    <div className="flex flex-col items-center justify-center w-full relative py-12 overflow-hidden">
      
      {/* Keyframes: ob-marquee-fwd / ob-marquee-rev — defined in globals.css */}
      <style dangerouslySetInnerHTML={{ __html: `
        @keyframes ob-marquee-fwd {
          from { transform: translateX(0); }
          to   { transform: translateX(-50%); }
        }
        @keyframes ob-marquee-rev {
          from { transform: translateX(-50%); }
          to   { transform: translateX(0); }
        }
        .ob-marquee-fwd {
          animation: ob-marquee-fwd 45s linear infinite;
        }
        .ob-marquee-rev {
          animation: ob-marquee-rev 50s linear infinite;
        }
      `}} />

      {/* Fade Masks — uses --ob-surface-0 token, not hardcoded hex */}
      <div className="pointer-events-none absolute inset-y-0 left-0 w-1/4 z-10"
        style={{ background: 'linear-gradient(to right, var(--ob-surface-0), transparent)' }} />
      <div className="pointer-events-none absolute inset-y-0 right-0 w-1/4 z-10"
        style={{ background: 'linear-gradient(to left, var(--ob-surface-0), transparent)' }} />

      {/* Row 1 - Moving Left */}
      <div className="flex w-full overflow-hidden mb-12 opacity-80 mix-blend-multiply dark:mix-blend-screen">
        <div className="flex w-max ob-marquee-fwd items-center text-neutral-400 dark:text-neutral-500">
           {[...logosRow1, ...logosRow1, ...logosRow1, ...logosRow1].map((logo, i) => (
             <div 
               key={i} 
               className="mx-12 md:mx-20 flex items-center justify-center whitespace-nowrap grayscale hover:grayscale-0 transition-all duration-300 cursor-default"
             >
               {logo.icon}
               <span className={logo.className}>
                 {logo.name}
               </span>
             </div>
           ))}
        </div>
      </div>

      {/* Row 2 - Moving Right (Reverse) */}
      <div className="flex w-full overflow-hidden opacity-80 mix-blend-multiply dark:mix-blend-screen hidden md:flex">
        <div className="flex w-max ob-marquee-rev items-center text-neutral-400 dark:text-neutral-500">
           {[...logosRow2, ...logosRow2, ...logosRow2, ...logosRow2].map((logo, i) => (
             <div 
               key={i} 
               className="mx-12 md:mx-20 flex items-center justify-center whitespace-nowrap grayscale hover:grayscale-0 transition-all duration-300 cursor-default"
             >
               {logo.icon}
               <span className={logo.className}>
                 {logo.name}
               </span>
             </div>
           ))}
        </div>
      </div>
      
    </div>
  )
}
Save to favoritesCopy to Figma
React

Infinite Marquee

A seamless infinite scrolling bar with multiple rows, reverse directions, and authentic SVGs.

Installation

$ npx @cosmoo/oblivion add infinite-marquee
Dependenciesnpm install

Usage Example

tsx
import InfiniteMarquee from "@/components/oblivion/infinite-marquee"

export default function Demo() {
  return (
    <div className="p-10 flex justify-center">
      <InfiniteMarquee />
    </div>
  )
}