Add this component

npx zentauri-ui add marquee

Accessibility notes

Keyboard accessible by default with semantic markup, visible focus treatment, and tokenized states. Add descriptive labels for icon-only or decorative usage.

Dependency notes

Check Installation for shared peers. This component keeps styling in Tailwind classes and the --zui-* token contract.

Display

Infinite tickers for logos, launches, and live product signals

Marquee renders a seamless auto-scrolling rail from the content you already have. Use it for brand logo rows, launch banners, testimonial snippets, activity signals, status tickers, and compact vertical release feeds.

Deploys synced99.98% uptimeAlerts routedData replicatedPolicies enforcedLaunch queue live
Launch queue livePolicies enforcedData replicatedAlerts routed99.98% uptimeDeploys synced

Examples

Marquee creates infinite logo rails, status tickers, release banners, and compact vertical feeds with CSS-only animation and duplicated children for seamless loops.


AtlasNorthstarPulseKernelLedgerCourier

v1.7.8

Marquee primitive shipped

v1.7.7

CountUp examples refreshed

v1.7.6

Charts SEO expanded

v1.7.5

Rating variants added


Usage alertsBilling syncedIncidents clear

Marquee variants playground

Pick an appearance, size, orientation, direction, and behavior to preview the marquee live. Toggle Show output / Show code and the snippet updates to match the selected variant.


Deploys syncedSecurity clearedSLO steadyLaunch-ready

All appearances

Every shipped appearance token at a glance. Click any swatch to load it into the playground above.

Marquee API

Generated from the package prop types and variant definitions.

Marquee

MarqueeProps

Variants

PropTypeDefault
appearance
aquabluecardcrimsoncyandefaultelectricemeraldforestghostgradient-bluegradient-green+32
default
fade
falsetrue
none
orientation
horizontalvertical
horizontal
size
lgmdsm
md

Behavior

PropTypeDefault
directionMarqueeDirection | undefinednone
gapstring | number | undefinednone
itemClassNamestring | undefinednone
pauseOnHoverboolean | undefinednone
speednumber | undefinednone
trackClassNamestring | undefinednone

Content

PropTypeDefault
children*ReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

MarqueeVariant

MarqueeVariantProps

Behavior

PropTypeDefault
appearance'default' | 'outline' | 'ghost' | 'card' | 'separated' | 'blue' | 'cyan' | 'green' | 'lime' | 'mint' | 'ocean' | 'sapphire' | 'lavender' | 'ruby' | 'red' | 'slate' | 'zinc' | 'stone' | 'royal' | 'electric' | 'forest' | 'sunset' | 'magenta' | 'crimson' | 'aqua' | 'plum' | 'sky' | 'rose' | 'purple' | 'pink' | 'orange' | 'yellow' | 'teal' | 'indigo' | 'emerald' | 'gradient-blue' | 'gradient-green' | 'gradient-red' | 'gradient-yellow' | 'gradient-purple' | 'gradient-teal' | 'gradient-indigo' | 'gradient-pink' | 'gradient-orange' | null | undefinednone
fadeboolean | null | undefinednone
orientation'horizontal' | 'vertical' | null | undefinednone
size'md' | 'sm' | 'lg' | null | undefinednone
CSS variable overrides

Marquee CSS variables

Override these Marquee variables on :root, a theme selector, or a component wrapper.

190 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-marquee-bg: transparent;
  --zui-marquee-fg: inherit;
  --zui-marquee-outline-border: oklch(86.9% 0.022 252.894);
  --zui-marquee-card-border: oklch(92.9% 0.013 255.508);
  --zui-marquee-card-bg: #ffffff;
  --zui-marquee-separated-border: oklch(86.9% 0.022 252.894);
  --zui-marquee-sky-border: oklch(62.3% 0.214 259.815 / 0.28);
  --zui-marquee-rose-border: oklch(58.6% 0.253 17.585 / 0.24);
  --zui-marquee-purple-border: oklch(62.7% 0.265 303.9 / 0.24);
  --zui-marquee-pink-border: oklch(65.6% 0.241 354.308 / 0.24);
  --zui-marquee-orange-border: oklch(70.5% 0.213 47.604 / 0.26);
  --zui-marquee-yellow-border: oklch(79.5% 0.184 86.047 / 0.3);
  --zui-marquee-teal-border: oklch(70.4% 0.14 182.503 / 0.28);
  --zui-marquee-indigo-border: oklch(58.5% 0.233 277.117 / 0.24);
  --zui-marquee-emerald-border: oklch(69.6% 0.17 162.48 / 0.28);
  --zui-marquee-gradient-blue-from: oklch(62.3% 0.214 259.815);
  --zui-marquee-gradient-blue-to: oklch(54.6% 0.245 262.881);
  --zui-marquee-gradient-green-from: oklch(72.3% 0.219 149.579);
  --zui-marquee-gradient-green-to: oklch(62.7% 0.194 149.214);
  --zui-marquee-gradient-red-from: oklch(63.7% 0.237 25.331);
  --zui-marquee-gradient-red-to: oklch(57.7% 0.245 27.325);
  --zui-marquee-gradient-yellow-from: oklch(85.2% 0.199 91.936);
  --zui-marquee-gradient-yellow-to: oklch(79.5% 0.184 86.047);
  --zui-marquee-gradient-purple-from: oklch(71.4% 0.203 305.504);
  --zui-marquee-gradient-purple-to: oklch(62.7% 0.265 303.9);
  --zui-marquee-gradient-teal-from: oklch(77.7% 0.152 181.912);
  --zui-marquee-gradient-teal-to: oklch(70.4% 0.14 182.503);
  --zui-marquee-gradient-indigo-from: oklch(67.3% 0.182 276.935);
  --zui-marquee-gradient-indigo-to: oklch(58.5% 0.233 277.117);
  --zui-marquee-gradient-pink-from: oklch(71.8% 0.202 349.761);
  --zui-marquee-gradient-pink-to: oklch(65.6% 0.241 354.308);
  --zui-marquee-gradient-orange-from: oklch(75% 0.183 55.934);
  --zui-marquee-gradient-orange-to: oklch(70.5% 0.213 47.604);
  --zui-marquee-blue-border: #2563eb;
  --zui-marquee-blue-bg: #2563eb14;
  --zui-marquee-blue-fg: #0f172a;
  --zui-marquee-cyan-border: #0891b2;
  --zui-marquee-cyan-bg: #0891b214;
  --zui-marquee-cyan-fg: #0f172a;
  --zui-marquee-green-border: #16a34a;
  --zui-marquee-green-bg: #16a34a14;
  --zui-marquee-green-fg: #0f172a;
  --zui-marquee-lime-border: #65a30d;
  --zui-marquee-lime-bg: #65a30d14;
  --zui-marquee-lime-fg: #0f172a;
  --zui-marquee-mint-border: #10b981;
  --zui-marquee-mint-bg: #10b98114;
  --zui-marquee-mint-fg: #0f172a;
  --zui-marquee-ocean-border: #0284c7;
  --zui-marquee-ocean-bg: #0284c714;
  --zui-marquee-ocean-fg: #0f172a;
  --zui-marquee-sapphire-border: #1d4ed8;
  --zui-marquee-sapphire-bg: #1d4ed814;
  --zui-marquee-sapphire-fg: #0f172a;
  --zui-marquee-lavender-border: #8b5cf6;
  --zui-marquee-lavender-bg: #8b5cf614;
  --zui-marquee-lavender-fg: #0f172a;
  --zui-marquee-ruby-border: #be123c;
  --zui-marquee-ruby-bg: #be123c14;
  --zui-marquee-ruby-fg: #0f172a;
  --zui-marquee-red-border: #dc2626;
  --zui-marquee-red-bg: #dc262614;
  --zui-marquee-red-fg: #0f172a;
  --zui-marquee-slate-border: #475569;
  --zui-marquee-slate-bg: #47556914;
  --zui-marquee-slate-fg: #0f172a;
  --zui-marquee-zinc-border: #52525b;
  --zui-marquee-zinc-bg: #52525b14;
  --zui-marquee-zinc-fg: #0f172a;
  --zui-marquee-stone-border: #57534e;
  --zui-marquee-stone-bg: #57534e14;
  --zui-marquee-stone-fg: #0f172a;
  --zui-marquee-royal-border: #4338ca;
  --zui-marquee-royal-bg: #4338ca14;
  --zui-marquee-royal-fg: #0f172a;
  --zui-marquee-electric-border: #0ea5e9;
  --zui-marquee-electric-bg: #0ea5e914;
  --zui-marquee-electric-fg: #0f172a;
  --zui-marquee-forest-border: #166534;
  --zui-marquee-forest-bg: #16653414;
  --zui-marquee-forest-fg: #0f172a;
  --zui-marquee-sunset-border: #ea580c;
  --zui-marquee-sunset-bg: #ea580c14;
  --zui-marquee-sunset-fg: #0f172a;
  --zui-marquee-magenta-border: #c026d3;
  --zui-marquee-magenta-bg: #c026d314;
  --zui-marquee-magenta-fg: #0f172a;
  --zui-marquee-crimson-border: #b91c1c;
  --zui-marquee-crimson-bg: #b91c1c14;
  --zui-marquee-crimson-fg: #0f172a;
  --zui-marquee-aqua-border: #0f766e;
  --zui-marquee-aqua-bg: #0f766e14;
  --zui-marquee-aqua-fg: #0f172a;
  --zui-marquee-plum-border: #7e22ce;
  --zui-marquee-plum-bg: #7e22ce14;
  --zui-marquee-plum-fg: #0f172a;
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-marquee-outline-border-dark: oklch(37.2% 0.044 257.287);
  --zui-marquee-card-border-dark: oklch(37.2% 0.044 257.287);
}

What it does

Marquee creates a continuous ticker by rendering two matching content groups and translating the track with CSS keyframes.

It supports horizontal and vertical movement, reverse directions, configurable gap and speed, optional fade masks, and pause-on-hover behavior.

Composition and API

Use Marquee as a wrapper around repeated items such as logo pills, cards, status badges, or testimonials. Configure appearance, size, orientation, direction, speed, gap, fade, and pauseOnHover from props while keeping the child markup fully yours.

Common use cases

  • Build continuous customer logo rails on marketing pages.
  • Show release notes, uptime signals, or status events without manual carousel controls.
  • Create compact testimonial or social-proof tickers.
  • Add vertical activity streams for product dashboards and changelogs.

Accessibility

Keep marquee content short and non-critical. If the ticker communicates important information, duplicate it elsewhere in static copy or provide an aria-label on the container that summarizes the purpose. Duplicate visual content is hidden from assistive technology.

Next.js integration notes

Marquee is a small client-safe component with no effects, timers, layout measurements, or browser APIs. It works well inside App Router pages while the surrounding SEO content remains server-rendered.

FAQ

Does Marquee require Framer Motion?

No. Marquee uses CSS keyframes and duplicated children, so it does not require Framer Motion or another animation dependency.

Can Marquee pause on hover?

Yes. Set pauseOnHover to pause the track when the user hovers the rail. Reduced-motion users also get a paused animation through motion-reduce styles.

Can Marquee scroll vertically?

Yes. Set orientation to vertical and use direction up or down. Provide a height with className when the default vertical height does not fit your layout.