# Marquee

> An endless CSS scroll of repeated content, horizontal or vertical, speed set with two CSS variables.

## Facts

- **Product**: Crew OS
- **Family**: Motion
- **Global**: `window.DigitalCrew.Marquee`
- **Source**: `digitalcrew-orchestrator: components/ui/marquee.tsx`
- **Import in the app**: `import { Marquee } from "@/components/ui/marquee";`
- **Live preview**: /design/components/marquee/preview.html
- **Page**: /design/components/marquee

## Guidelines

**Use it for** logo strips, integration chips and testimonial columns (the vertical testimonial wall is three Marquees). Content must still make sense if the user never sees it all.

**What you provide**: `children` (one set of items, repeated for you), `repeat` (default 4), `reverse` (default false), `vertical` (default false), `pauseOnHover` (default false), `className`. Speed and spacing come from CSS variables set in `className`: `--duration` (default `40s`) and `--gap` (default `1rem`), for example `[--duration:30s] [--gap:0.75rem]`.

**Anatomy**: a `flex` row (or column) with `overflow-hidden`, 8px padding and `--gap` between copies and between items. Add edge fades yourself (`bg-gradient-to-r from-background` overlays, as in this preview).

**Behaviour**: each copy runs `marquee` (translateX from 0 to `calc(-100% - var(--gap))`) or `marquee-vertical`, linear and infinite, over `--duration`; `reverse` flips the direction and `pauseOnHover` pauses the animation while hovered. There is no reduced-motion branch in the component; pause it (`[animation-play-state:paused]`) for users who ask for less motion.

**Don't** put links or buttons that must be clicked in a moving row, or set a duration so short the text cannot be read.

## API

```ts
interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
    /**
     * Optional CSS class name to apply custom styles
     */
    className?: string;
    /**
     * Whether to reverse the animation direction
     * @default false
     */
    reverse?: boolean;
    /**
     * Whether to pause the animation on hover
     * @default false
     */
    pauseOnHover?: boolean;
    /**
     * Content to be displayed in the marquee
     */
    children: React.ReactNode;
    /**
     * Whether to animate vertically instead of horizontally
     * @default false
     */
    vertical?: boolean;
    /**
     * Number of times to repeat the content
     * @default 4
     */
    repeat?: number;
}
export declare function Marquee({ className, reverse, pauseOnHover, children, vertical, repeat, ...props }: MarqueeProps): JSX.Element;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  var tools = [["Gmail", I.Mail], ["LinkedIn", I.Linkedin], ["Aircall", I.Phone], ["Google Calendar", I.Calendar], ["Google Meet", I.Video], ["HubSpot", I.Target]];
  var quotes = [
    ["Booked 11 meetings in the first week.", "Omar Haddad, VP Finance"],
    ["Replies are triaged before I open my inbox.", "Claire Dubois, CFO"],
    ["Our SDRs finally work the warm leads only.", "Lena Fischer, Head of Sales"],
    ["Follow-ups never slip anymore.", "Marc Lefèvre, Founder"]
  ];
  function App() {
    return h("div", { className: "relative grid gap-1" },
      h(DC.Marquee, { pauseOnHover: true, className: "[--duration:30s]" },
        tools.map(function (t) { return h("span", { key: t[0], className: "inline-flex items-center gap-2 rounded-full border bg-card px-3 py-1.5 text-sm" }, h(t[1], { className: "size-4" }), t[0]); })),
      h(DC.Marquee, { reverse: true, pauseOnHover: true, className: "[--duration:45s] [--gap:0.75rem]" },
        quotes.map(function (q) { return h("span", { key: q[1], className: "inline-flex items-center gap-2 whitespace-nowrap rounded-lg bg-accent px-3 py-2 text-sm" }, "“" + q[0] + "”", h("span", { className: "text-muted-foreground text-xs" }, q[1])); })),
      h("div", { className: "pointer-events-none absolute inset-y-0 left-0 w-16 bg-gradient-to-r from-background" }),
      h("div", { className: "pointer-events-none absolute inset-y-0 right-0 w-16 bg-gradient-to-l from-background" }));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Motion

- [ActionFocusSession](/design/components/action-focus-session.md): The focus timebox for one task in the actions cockpit: a live billable clock with approve, start, pause, run and done, and a burst of sparkles on completion.
- [CardResize](/design/components/card-resize.md): A container that tweens its width and height when its content changes (`.t-resize`).
- [ChapterScrubber](/design/components/chapter-scrubber.md): A rail of ticks, one per chapter, that swell like a dock under the pointer, with a card previewing the hovered chapter.
- [ContainerScroll](/design/components/container-scroll.md): A hero block where a device-like frame starts tilted back in 3D and straightens as the page scrolls, with the title drifting up.
- [FeatureSlideshow](/design/components/feature-slideshow.md): A step-by-step feature explainer: an accordion of steps on the left that advances on a timer, a progress line on the open step, and a large media slot on the right.
- [FirstBentoAnimation](/design/components/first-bento-animation.md): A self-playing chat vignette for the bento grid: a user asks for a meeting slot, the Digital Crew avatar shows typing dots, then the reply streams in as a `Reasoning` block.
- [FourthBentoAnimation](/design/components/fourth-bento-animation.md): A scheduling vignette for the bento grid: a week ruler, three task bars that spring into place, and a time cursor that follows the pointer.
- [HyperText](/design/components/hyper-text.md): A monospaced, uppercase text effect: letters scramble through random characters, then lock in from left to right.
- [InfiniteSlider](/design/components/infinite-slider.md): A JavaScript-driven endless strip (Framer Motion) that renders its children twice and slides them in a loop, optionally slowing on hover.
- [JoyfulTaskCheckbox](/design/components/joyful-task-checkbox.md): A task checkbox with a small, restrained completion moment: one soft bloom, two sparks, then stillness.
- [Lottie](/design/components/lottie.md): The lottie-react player, exported as-is, for the Lottie animations that ship with Crew OS (`animations/*.json`).
- [MotionScale](/design/components/motion-scale.md): The shared motion scale made visible: the same distance travelled on each duration token and each easing, with a Replay button.
- [NumberFlowCounter](/design/components/number-flow-counter.md): A small dark pill that shows one number at a time and rolls its digits to the next value every two seconds (NumberFlow).
- [OrbitingCircles](/design/components/orbiting-circles.md): Places its children on a circular orbit around the centre of the parent and spins them, with an optional faint ring for the path.
- [ShimmerText](/design/components/shimmer-text.md): A status line with a light band sweeping across its glyphs — Max's "Thinking…" and live tool lines (`.t-shimmer`).
- [SignatureGradient](/design/components/signature-gradient.md): The signature Digital Crew gradient — indigo → pink → amber (`dc-andre`, `dc-camille`, `dc-amber`) — in its four forms.
- [SkeletonReveal](/design/components/skeleton-reveal.md): A skeleton that cross-blurs into the loaded content, so the swap reads as one motion (`.t-skel`).
- [StreamingText](/design/components/streaming-text.md): Streamed words resolving through a soft cross-blur, one after another (`.t-stream-w` → `.is-in`).
- [ThirdBentoAnimation](/design/components/third-bento-animation.md): An insight vignette for the bento grid: a smooth area line draws itself, a dot pulses at its midpoint and a dark pill above it ticks through values.
- [UniboxMotion](/design/components/unibox-motion.md): The Unibox's shared motion vocabulary: every surface moves on the same few springs, so the whole inbox feels like one physical material.
