Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Components

Free

Marquee for Solid

A moving strip of logos or cards that loops by itself, instead of waiting for someone to press next. For Solid with Ark UI, when the motion is decoration.

Framework
UI library

Logos or cards leave one edge and come back on the other, with no next button.

Use it on a marketing page when the motion is decoration and the items can repeat. If someone should stop on a specific slide, use a Carousel. In Solid, Ark UI runs the loop, holds it while someone points at it or tabs into it, and keeps it still for people who ask for reduced motion.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Marquee anatomy: root, edge, item, content
Marquee
├── MarqueeContent
│   └── MarqueeViewport
├── MarqueeEdge
└── MarqueeItem

Usage

import { AppleIcon } from "@/components/icons/apple";
import { ChatGptIcon } from "@/components/icons/chat-gpt";
import { ClaudeIcon } from "@/components/icons/claude";
import { GoogleIcon } from "@/components/icons/google";
import { NextIcon } from "@/components/icons/next";
import { ReactIcon } from "@/components/icons/react";
import { ViteIcon } from "@/components/icons/vite";
import { VueIcon } from "@/components/icons/vue";
import { Card, CardContent } from "@/components/ui/card";
import {
  Marquee, MarqueeContent, MarqueeItem,
} from "@/components/ui/marquee";
const MarqueeDemo = () => (
  <Marquee>
    <MarqueeContent>
      {items.map((Icon, index) => (
        <MarqueeItem key={index}>
          <Card class="[--space:--spacing(8)]">
            <CardContent>
              <Icon class="size-10" />
            </CardContent>
          </Card>
        </MarqueeItem>
      ))}
    </MarqueeContent>
  </Marquee>
);

const items = [
  GoogleIcon,
  AppleIcon,
  NextIcon,
  ChatGptIcon,
  ClaudeIcon,
  ViteIcon,
  VueIcon,
  ReactIcon,
];

Accessibility

The loop holds while the pointer is over it or focus is inside it, and runs again once both have left; pauseOnInteraction is on by default. With reduced motion on, nothing moves: the items stay in place, the edge fades go, and a row longer than the frame scrolls instead. The copies that make the loop are hidden from screen readers and inert, so each item is read and tabbed to once.

End
Go to the end.

Demos

Autofill

A short logo list leaves a gap before the loop comes around, so autoFill copies items until the track is full. This row also runs at a speed of 100, twice the default of 50 pixels a second, which is a lot for words and reasonable for logos. Use autofill whenever the set is shorter than the frame, or the seam shows.

Preview width

Custom Speed

speed counts pixels per second, defaulting to 50. This row uses 10, slow enough that a name could be read, which is what you want for words and too sleepy for a logo wall. Set it on Marquee, not on each card, and leave the gap alone, because spacing is a different prop.

Preview width

Fade

The ends fade out unless showEdges is off. The first row clips logos hard at the frame, and the second keeps the fade while reverse runs them the other way, so the soft edge is easier to see against the motion. The fade is a mask on the marquee itself, not a band of colour, so it dissolves into whatever is behind: the page, a card, a tinted band or a photo.

Preview width

Orientation Horizontal

Sideways travel is the default. Setting orientation to horizontal only makes that obvious, which helps when a vertical strip is on the same page or the value is controlled. The cards move in a row and the height follows them. A page with one logo bar can omit the prop and get this direction anyway.

Preview width

Orientation Vertical

orientation set to vertical stacks the cards and moves them up. The column is narrow and height-capped, because a vertical loop with no limit has nowhere to scroll, which suits a sidebar better than a hero. The edge fade stays at the top and bottom unless you turn it off.

Preview width

Pause On Hover

pauseOnInteraction is on by default, and this demo sets it only to show the prop: the loop holds while the pointer is over the strip or focus is inside, then resumes on the way out. Keep it on when a logo is a link or a name has to be read, because a moving target is a poor place to click. Turn it off only when something else can stop the strip, such as a button that sets paused.

Preview width

Reverse

reverse sends the cards the other way, which is how a second strip under a forward one reads as two bands instead of one belt. Speed and the original order of the items stay as they are. Use the flip for that paired layout, or when the motion should follow the reading direction, without inventing a negative duration yourself.

Preview width

Spacing

spacing is a CSS length for the gap between cards and between the copies that form the loop. The default is 16px, and this row uses 40px; hover it to hold the loop and look at the gap instead of watching it fly past. Widen it when logos feel stuck together, and do not fake the distance with a gap class on the item.

Preview width

FAQ

How do I change the speed of a Marquee?

Set speed to pixels per second, with a default of 50, and use a lower number for a slower loop as the custom speed demo does. spacing is the gap between copies and defaults to 16px on this component, while reverse flips the travel direction. Both props belong on Marquee, not on each item.

How do I pause a Marquee on hover in Solid?

It pauses by default: pauseOnInteraction is true, so hovering the marquee or moving focus into it pauses the loop, and leaving resumes it. Set it to false to keep the loop running, or pass paused when you want to control it yourself. onPauseChange receives details.paused whenever that state flips.

How do I make a vertical Marquee?

Set orientation to vertical so the root's data-orientation switches the loop from horizontal to vertical, or leave the default horizontal. showEdges defaults to true and fades the two ends (the top and bottom when vertical) with a mask, and setting it to false removes those fades.

Does a Marquee loop forever?

Yes, until you set loopCount. The default 0 means infinite. A number above 0 stops after that many loops, and onComplete runs only for those finite loops. autoFill duplicates the items until they fill the container, which avoids a gap when the list is shorter than the frame.

Is a Marquee accessible from the keyboard?

Yes. Tabbing to a link inside it pauses the loop until focus leaves, as hovering does. The copies that make the loop are hidden from screen readers and inert, so each item is read and reached once. With reduced motion on, nothing moves, and a row longer than the frame scrolls instead. Still treat the motion as decoration, and do not put information only in a marquee.

How do I style a Marquee with Ark UI?

Edit the marquee file under components/ui, where duration, spacing, delay, and loop count are the custom properties --marquee-duration, --marquee-spacing, --marquee-delay, and --marquee-loop-count. The root sets data-paused, data-orientation and data-pause-on-interaction, and content sets data-reverse while reverse is on. The edge fade is a mask on the root (mask-x-from-75%, or mask-y-from-75% when vertical), so it needs no colour to match the surface behind it; MarqueeEdge, still exported, paints a band from the background colour if you want a fade in a colour of your own.

How do I install Marquee in Solid?

Run the command in the Installation section on this page. It adds Marquee, MarqueeContent, and MarqueeItem to your ui folder, which is enough for a looping row. Import those parts from that folder and put one item per entry inside the content. The command uses the shadcn CLI.

API Reference

Marquee

<div> data-slot="marquee"

PropType
autoFill?boolean

Whether to automatically duplicate content to fill the container.

Default
false
defaultPaused?boolean

Whether the marquee is paused by default.

Default
false
delay?number

The delay before the animation starts (in seconds).

Default
0
dir?"ltr" | "rtl"

The document's text/writing direction.

Type
"ltr" | "rtl"
Default
"ltr"
id?string

The unique identifier of the machine.

ids?object

The ids of the elements in the marquee. Useful for composition.

Type
{ root?: string; viewport?: string; content?: (index: number) → string }
loopCount?number

The number of times to loop the animation (0 = infinite).

Default
0
onComplete?() → void

Function called when the marquee completes all loops and stops. Only fires for finite loops (loopCount > 0).

Returns
void
onLoopComplete?() → void

Function called when the marquee completes one loop iteration.

Returns
void
onPauseChange?(details: PauseStatusDetails) → void

Function called when the pause status changes.

Type
(details: PauseStatusDetails) → void
Parameters

details – { paused: boolean }

Returns
void
orientation?"horizontal" | "vertical"

Scrolls side to side (horizontal) or up and down (vertical).

Type
"horizontal" | "vertical"
Default
"horizontal"
paused?boolean

Whether the marquee is paused.

pauseOnInteraction?boolean

Whether to pause the marquee on user interaction (hover, focus). Ark default: false.

Default
true
reverse?boolean

Whether to reverse the animation direction.

Default
false
showEdges?boolean

Whether the ends fade out. The fade is a mask, so it fades into whatever is behind the marquee (a card, a tinted band, an image).

Default
true
spacing?string

The spacing between marquee items. Ark default: 1rem.

Default
"16px"
speed?number

The speed of the marquee animation in pixels per second.

Default
50
translations?object

The localized messages to use.

Type
{ root?: string }
asChild?(props: ParentProps) => JSX.Element

Render your own element: a function that gets the part's props to spread on it.

Type
(props: ParentProps) => JSX.Element
class?string

Merged with the part's classes.

AttributeType
data-orientation?string

The orientation of the marquee.

data-pause-on-interaction?string

Present when pauseOnInteraction is true.

data-paused?string

Present when paused.

data-state"paused" | "idle"

"paused" or "idle".

Type
"paused" | "idle"
CSS variableType
--marquee-delaystring

The marquee delay value for the Root.

--marquee-durationstring

The marquee duration value for the Root.

--marquee-loop-countstring

The marquee loop count value for the Root.

--marquee-spacingstring

The marquee spacing value for the Root.

--marquee-translatestring

The marquee translate value for the Root.

MarqueeViewport

<div> data-slot="marquee-viewport"

PropType
asChild?(props: ParentProps) => JSX.Element

Render your own element: a function that gets the part's props to spread on it.

Type
(props: ParentProps) => JSX.Element
AttributeType
data-orientation"horizontal" | "vertical"

The orientation of the viewport.

Type
"horizontal" | "vertical"
data-side"top" | "right" | "bottom" | "left"

The side of the trigger that the viewport is positioned on.

Type
"top" | "right" | "bottom" | "left"
CSS variableType
--marquee-delaystring

MarqueeContent

<div> data-slot="marquee-content"

PropType
asChild?(props: ParentProps) => JSX.Element

Render your own element: a function that gets the part's props to spread on it.

Type
(props: ParentProps) => JSX.Element
class?string

Merged with the part's classes.

AttributeType
data-clone?string

Present when clone is true.

data-indexstring

The index of the item.

data-orientation"horizontal" | "vertical"

The orientation of the content.

Type
"horizontal" | "vertical"
data-reversestring
data-side"top" | "right" | "bottom" | "left"

The side of the trigger that the content is positioned on.

Type
"top" | "right" | "bottom" | "left"
CSS variableType
--marquee-delaystring

MarqueeEdge

<div> data-slot="marquee-edge"

PropType
side"start" | "end" | "top" | "bottom"

The side where the edge gradient should appear.

Type
"start" | "end" | "top" | "bottom"
asChild?(props: ParentProps) => JSX.Element

Render your own element: a function that gets the part's props to spread on it.

Type
(props: ParentProps) => JSX.Element
class?string

Merged with the part's classes.

AttributeType
data-orientation"horizontal" | "vertical"

The orientation of the edge.

Type
"horizontal" | "vertical"
data-side"top" | "right" | "bottom" | "left"

The side of the trigger that the edge is positioned on.

Type
"top" | "right" | "bottom" | "left"

MarqueeItem

<div> data-slot="marquee-item"

PropType
asChild?(props: ParentProps) => JSX.Element

Render your own element: a function that gets the part's props to spread on it.

Type
(props: ParentProps) => JSX.Element
class?string

Merged with the part's classes.

With other components