Getting Started
Blocks
Components
Device Mocks
Special Effects
Animations
Text Animations
Buttons
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jane
I'm at a loss for words. This is amazing. I love it.
@jenny
I'm at a loss for words. This is amazing. I love it.
@james
I'm at a loss for words. This is amazing. I love it.
@jane
I'm at a loss for words. This is amazing. I love it.
@jenny
I'm at a loss for words. This is amazing. I love it.
@james
I'm at a loss for words. This is amazing. I love it.
@jane
I'm at a loss for words. This is amazing. I love it.
@jenny
I'm at a loss for words. This is amazing. I love it.
@james
I'm at a loss for words. This is amazing. I love it.
@jane
I'm at a loss for words. This is amazing. I love it.
@jenny
I'm at a loss for words. This is amazing. I love it.
@james
I'm at a loss for words. This is amazing. I love it.
import { cn } from "@/lib/utils";
import { Marquee } from "@/registry/magicui/marquee";
const reviews = [
{
name: "Jack",
username: "@jack",
body: "I've never seen anything like this before. It's amazing. I love it.",
img: "https://avatar.vercel.sh/jack",
},
{
name: "Jill",
username: "@jill",
body: "I don't know what to say. I'm speechless. This is amazing.",
img: "https://avatar.vercel.sh/jill",
},
{
name: "John",
username: "@john",
body: "I'm at a loss for words. This is amazing. I love it.",
img: "https://avatar.vercel.sh/john",
},
{
name: "Jane",
username: "@jane",
body: "I'm at a loss for words. This is amazing. I love it.",
img: "https://avatar.vercel.sh/jane",
},
{
name: "Jenny",
username: "@jenny",
body: "I'm at a loss for words. This is amazing. I love it.",
img: "https://avatar.vercel.sh/jenny",
},
{
name: "James",
username: "@james",
body: "I'm at a loss for words. This is amazing. I love it.",
img: "https://avatar.vercel.sh/james",
},
];
const firstRow = reviews.slice(0, reviews.length / 2);
const secondRow = reviews.slice(reviews.length / 2);
const ReviewCard = ({
img,
name,
username,
body,
}: {
img: string;
name: string;
username: string;
body: string;
}) => {
return (
<figure
className={cn(
"relative h-full w-64 cursor-pointer overflow-hidden rounded-xl border p-4",
// light styles
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05]",
// dark styles
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]",
)}
>
<div className="flex flex-row items-center gap-2">
<img className="rounded-full" width="32" height="32" alt="" src={img} />
<div className="flex flex-col">
<figcaption className="text-sm font-medium dark:text-white">
{name}
</figcaption>
<p className="text-xs font-medium dark:text-white/40">{username}</p>
</div>
</div>
<blockquote className="mt-2 text-sm">{body}</blockquote>
</figure>
);
};
export function MarqueeDemo() {
return (
<div className="relative flex w-full flex-col items-center justify-center overflow-hidden">
<Marquee pauseOnHover className="[--duration:20s]">
{firstRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<Marquee reverse pauseOnHover className="[--duration:20s]">
{secondRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/4 bg-gradient-to-r from-background"></div>
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/4 bg-gradient-to-l from-background"></div>
</div>
);
}
Installation
pnpm dlx shadcn@latest add @magicui/marquee
Examples
Vertical
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
/* eslint-disable @next/next/no-img-element */
import { cn } from "@/lib/utils";
import { Marquee } from "@/registry/magicui/marquee";
const reviews = [
{
name: "Jack",
username: "@jack",
body: "I've never seen anything like this before. It's amazing. I love it.",
img: "https://avatar.vercel.sh/jack",
},
{
name: "Jill",
username: "@jill",
body: "I don't know what to say. I'm speechless. This is amazing.",
img: "https://avatar.vercel.sh/jill",
},
{
name: "John",
username: "@john",
body: "I'm at a loss for words. This is amazing. I love it.",
img: "https://avatar.vercel.sh/john",
},
];
const firstRow = reviews.slice(0, reviews.length / 2);
const secondRow = reviews.slice(reviews.length / 2);
const ReviewCard = ({
img,
name,
username,
body,
}: {
img: string;
name: string;
username: string;
body: string;
}) => {
return (
<figure
className={cn(
"relative h-full w-fit sm:w-36 cursor-pointer overflow-hidden rounded-xl border p-4",
// light styles
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05]",
// dark styles
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]",
)}
>
<div className="flex flex-row items-center gap-2">
<img className="rounded-full" width="32" height="32" alt="" src={img} />
<div className="flex flex-col">
<figcaption className="text-sm font-medium dark:text-white">
{name}
</figcaption>
<p className="text-xs font-medium dark:text-white/40">{username}</p>
</div>
</div>
<blockquote className="mt-2 text-sm">{body}</blockquote>
</figure>
);
};
export function MarqueeDemoVertical() {
return (
<div className="relative flex h-[500px] w-full flex-row items-center justify-center overflow-hidden">
<Marquee pauseOnHover vertical className="[--duration:20s]">
{firstRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<Marquee reverse pauseOnHover vertical className="[--duration:20s]">
{secondRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<div className="pointer-events-none absolute inset-x-0 top-0 h-1/4 bg-gradient-to-b from-background"></div>
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-1/4 bg-gradient-to-t from-background"></div>
</div>
);
}
3D
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jack
I've never seen anything like this before. It's amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
@jill
I don't know what to say. I'm speechless. This is amazing.
@john
I'm at a loss for words. This is amazing. I love it.
/* eslint-disable @next/next/no-img-element */
import { cn } from "@/lib/utils";
import { Marquee } from "@/registry/magicui/marquee";
const reviews = [
{
name: "Jack",
username: "@jack",
body: "I've never seen anything like this before. It's amazing. I love it.",
img: "https://avatar.vercel.sh/jack",
},
{
name: "Jill",
username: "@jill",
body: "I don't know what to say. I'm speechless. This is amazing.",
img: "https://avatar.vercel.sh/jill",
},
{
name: "John",
username: "@john",
body: "I'm at a loss for words. This is amazing. I love it.",
img: "https://avatar.vercel.sh/john",
},
];
const firstRow = reviews.slice(0, reviews.length / 2);
const secondRow = reviews.slice(reviews.length / 2);
const thirdRow = reviews.slice(0, reviews.length / 2);
const fourthRow = reviews.slice(reviews.length / 2);
const ReviewCard = ({
img,
name,
username,
body,
}: {
img: string;
name: string;
username: string;
body: string;
}) => {
return (
<figure
className={cn(
"relative h-full w-fit sm:w-36 cursor-pointer overflow-hidden rounded-xl border p-4",
// light styles
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05]",
// dark styles
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]",
)}
>
<div className="flex flex-row items-center gap-2">
<img className="rounded-full" width="32" height="32" alt="" src={img} />
<div className="flex flex-col">
<figcaption className="text-sm font-medium dark:text-white">
{name}
</figcaption>
<p className="text-xs font-medium dark:text-white/40">{username}</p>
</div>
</div>
<blockquote className="mt-2 text-sm">{body}</blockquote>
</figure>
);
};
export function Marquee3D() {
return (
<div className="relative flex h-96 w-full flex-row items-center justify-center gap-4 overflow-hidden [perspective:300px]">
<div
className="flex flex-row items-center gap-4"
style={{
transform:
"translateX(-100px) translateY(0px) translateZ(-100px) rotateX(20deg) rotateY(-10deg) rotateZ(20deg)",
}}
>
<Marquee pauseOnHover vertical className="[--duration:20s]">
{firstRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<Marquee reverse pauseOnHover className="[--duration:20s]" vertical>
{secondRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<Marquee reverse pauseOnHover className="[--duration:20s]" vertical>
{thirdRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
<Marquee pauseOnHover className="[--duration:20s]" vertical>
{fourthRow.map((review) => (
<ReviewCard key={review.username} {...review} />
))}
</Marquee>
</div>
<div className="pointer-events-none absolute inset-x-0 top-0 h-1/4 bg-gradient-to-b from-background"></div>
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-1/4 bg-gradient-to-t from-background"></div>
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/4 bg-gradient-to-r from-background"></div>
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/4 bg-gradient-to-l from-background"></div>
</div>
);
}
Usage
import { Marquee } from "@/components/magicui/marquee";
<Marquee>
<span>Next.js</span>
<span>React</span>
<span>TypeScript</span>
<span>Tailwind CSS</span>
</Marquee>
Props
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | The class name to apply to the component. |
reverse | boolean | false | Whether or not to reverse the direction of the marquee. |
pauseOnHover | boolean | false | Whether or not to pause the marquee when the user hovers over the component. |
vertical | boolean | false | Whether or not to display the marquee vertically. |
children | node | - | The content to display in the marquee. |
repeat | number | 4 | The number of times to repeat the content. |
Limited Time Offer
Ship Faster with Magic UI ProMagic UI Pro
Stop building from scratch.
Get 8 production-ready templates and 50+ premium components that your users will love.
✓
Next.js 15 + TypeScript ready✓
Copy, paste, customize in minutes✓
Save 100+ hours of development