Marquee
Create a continuous scrolling display of logos, images, or text horizontally or vertically
'use client'
import { Marquee } from '@chakra-ui/react'
import {
IoLogoFigma,
IoLogoGitlab,
IoLogoJavascript,
IoLogoLinkedin,
IoLogoTwitter,
IoLogoVimeo,
} from 'react-icons/io5'
export const MarqueeBasic = () => (
<Marquee.Root autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} px="2rem">
<item.icon size="3rem" aria-label={item.label} color={item.color} />
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
const items = [
{ icon: IoLogoFigma, label: 'Figma', color: '#F24E1E' },
{ icon: IoLogoTwitter, label: 'Twitter', color: '#1da1f2' },
{ icon: IoLogoLinkedin, label: 'LinkedIn', color: '#0077b5' },
{ icon: IoLogoGitlab, label: 'GitLab', color: '#fc6d26' },
{ icon: IoLogoVimeo, label: 'Vimeo', color: '#1ab7ea' },
{ icon: IoLogoJavascript, label: 'JavaScript', color: '#f7df1e' },
]
Anatomy
import { Marquee } from '@chakra-ui/react'<Marquee.Root>
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item />
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>Use the autoFill prop to repeat the items until the viewport is filled, and
the spacing prop to control the gap between the repeated groups.
Examples
Reversed
Use the reverse prop on the Marquee.Root component to reverse the direction
of the marquee.
'use client'
import { Marquee } from '@chakra-ui/react'
import {
IoLogoFigma,
IoLogoGitlab,
IoLogoJavascript,
IoLogoLinkedin,
IoLogoTwitter,
IoLogoVimeo,
} from 'react-icons/io5'
export const MarqueeReverseDirection = () => (
<Marquee.Root reverse autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} px="2rem">
<item.icon size="3rem" aria-label={item.label} color={item.color} />
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
const items = [
{ icon: IoLogoFigma, label: 'Figma', color: '#F24E1E' },
{ icon: IoLogoTwitter, label: 'Twitter', color: '#1da1f2' },
{ icon: IoLogoLinkedin, label: 'LinkedIn', color: '#0077b5' },
{ icon: IoLogoGitlab, label: 'GitLab', color: '#fc6d26' },
{ icon: IoLogoVimeo, label: 'Vimeo', color: '#1ab7ea' },
{ icon: IoLogoJavascript, label: 'JavaScript', color: '#f7df1e' },
]
Vertical
To animate content along the Y axis, use the side prop and set it to bottom.
'use client'
import { Marquee } from '@chakra-ui/react'
import {
IoLogoFigma,
IoLogoGitlab,
IoLogoJavascript,
IoLogoLinkedin,
IoLogoTwitter,
IoLogoVimeo,
} from 'react-icons/io5'
export const MarqueeVerticalAnimation = () => (
<Marquee.Root side="bottom" height="300px" spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} px="2rem">
<item.icon size="3rem" aria-label={item.label} color={item.color} />
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
const items = [
{ icon: IoLogoFigma, label: 'Figma', color: '#F24E1E' },
{ icon: IoLogoTwitter, label: 'Twitter', color: '#1da1f2' },
{ icon: IoLogoLinkedin, label: 'LinkedIn', color: '#0077b5' },
{ icon: IoLogoGitlab, label: 'GitLab', color: '#fc6d26' },
{ icon: IoLogoVimeo, label: 'Vimeo', color: '#1ab7ea' },
{ icon: IoLogoJavascript, label: 'JavaScript', color: '#f7df1e' },
]
Speed
Use the speed prop to control the animation speed in pixels per second.
'use client'
import { For, Marquee, Span, Stack } from '@chakra-ui/react'
import {
IoLogoFigma,
IoLogoGitlab,
IoLogoJavascript,
IoLogoLinkedin,
IoLogoTwitter,
IoLogoVimeo,
} from 'react-icons/io5'
const speeds = [
{ value: 25, label: 'Slow (25px/s)' },
{ value: 50, label: 'Normal (50px/s)' },
{ value: 100, label: 'Fast (100px/s)' },
]
export const MarqueeWithSpeed = () => (
<Stack gap="12">
<For each={speeds}>
{(speed) => (
<Stack key={speed.value} gap="4">
<Span fontWeight="medium" textStyle="sm">
{speed.label}
</Span>
<Marquee.Root speed={speed.value} autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} px="2rem">
<item.icon
size="3rem"
aria-label={item.label}
color={item.color}
/>
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</Stack>
)}
</For>
</Stack>
)
const items = [
{ icon: IoLogoFigma, label: 'Figma', color: '#F24E1E' },
{ icon: IoLogoTwitter, label: 'Twitter', color: '#1da1f2' },
{ icon: IoLogoLinkedin, label: 'LinkedIn', color: '#0077b5' },
{ icon: IoLogoGitlab, label: 'GitLab', color: '#fc6d26' },
{ icon: IoLogoVimeo, label: 'Vimeo', color: '#1ab7ea' },
{ icon: IoLogoJavascript, label: 'JavaScript', color: '#f7df1e' },
]
Pause On Interaction
Use the pauseOnInteraction prop to pause the animation when the user hovers or
focuses the marquee.
'use client'
import { Marquee } from '@chakra-ui/react'
import {
IoLogoFigma,
IoLogoGitlab,
IoLogoJavascript,
IoLogoLinkedin,
IoLogoTwitter,
IoLogoVimeo,
} from 'react-icons/io5'
export const MarqueePauseInteractions = () => (
<Marquee.Root pauseOnInteraction autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} px="2rem">
<item.icon size="3rem" aria-label={item.label} color={item.color} />
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
const items = [
{ icon: IoLogoFigma, label: 'Figma', color: '#F24E1E' },
{ icon: IoLogoTwitter, label: 'Twitter', color: '#1da1f2' },
{ icon: IoLogoLinkedin, label: 'LinkedIn', color: '#0077b5' },
{ icon: IoLogoGitlab, label: 'GitLab', color: '#fc6d26' },
{ icon: IoLogoVimeo, label: 'Vimeo', color: '#1ab7ea' },
{ icon: IoLogoJavascript, label: 'JavaScript', color: '#f7df1e' },
]
Edge Gradient
Render the Marquee.Edge component to apply an edge fade.
'use client'
import { Marquee } from '@chakra-ui/react'
import {
IoLogoFigma,
IoLogoGitlab,
IoLogoJavascript,
IoLogoLinkedin,
IoLogoTwitter,
IoLogoVimeo,
} from 'react-icons/io5'
export const MarqueeEdgeGradient = () => (
<Marquee.Root autoFill spacing="2rem">
<Marquee.Edge side="start" />
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} px="2rem">
<item.icon size="3rem" aria-label={item.label} color={item.color} />
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
<Marquee.Edge side="end" />
</Marquee.Root>
)
const items = [
{ icon: IoLogoFigma, label: 'Figma', color: '#F24E1E' },
{ icon: IoLogoTwitter, label: 'Twitter', color: '#1da1f2' },
{ icon: IoLogoLinkedin, label: 'LinkedIn', color: '#0077b5' },
{ icon: IoLogoGitlab, label: 'GitLab', color: '#fc6d26' },
{ icon: IoLogoVimeo, label: 'Vimeo', color: '#1ab7ea' },
{ icon: IoLogoJavascript, label: 'JavaScript', color: '#f7df1e' },
]
Testimonials
You can display testimonials with the marquee component.
'use client'
import { Avatar, Box, Card, HStack, Marquee, Stack } from '@chakra-ui/react'
import { IoStar } from 'react-icons/io5'
export const MarqueeWithTestimonials = () => (
<Marquee.Root pauseOnInteraction py="10">
<Marquee.Edge side="start" />
<Marquee.Viewport>
<Marquee.Content>
{testimonials.map((item, i) => (
<Marquee.Item key={i} px="1rem">
<TestimonialCard item={item} />
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
<Marquee.Edge side="end" />
</Marquee.Root>
)
const TestimonialCard = ({ item }: { item: Testimonial }) => {
return (
<Card.Root maxW="sm" h="full">
<Card.Body>
<Stack gap="3">
<HStack gap="1">
{Array.from({ length: item.rating }).map((_, i) => (
<Box as={IoStar} key={i} color="orange.solid" />
))}
</HStack>
<Card.Description color="fg.muted" textStyle="md" minH="16">
“{item.content}”
</Card.Description>
<HStack gap="3" mt="1">
<Avatar.Root size="sm">
<Avatar.Image src={item.avatar} />
<Avatar.Fallback name={item.name} />
</Avatar.Root>
<Box textStyle="sm">
<Box fontWeight="medium" color="fg">
{item.name}
</Box>
<Box color="fg.muted">{item.role}</Box>
</Box>
</HStack>
</Stack>
</Card.Body>
</Card.Root>
)
}
interface Testimonial {
name: string
role: string
rating: number
avatar: string
content: string
}
const testimonials: Testimonial[] = [
{
name: 'Sarah Chen',
role: 'Product Designer',
rating: 5,
avatar: 'https://i.pravatar.cc/150?u=a042581f4e29026024d',
content:
'This library saved me weeks of work. The components are accessible and easy to customize.',
},
{
name: 'Michael Torres',
role: 'Frontend Dev',
rating: 4,
avatar: 'https://i.pravatar.cc/150?u=a042581f4e29026704d',
content:
'The animations are buttery smooth. I love how easy it is to implement the marquee.',
},
{
name: 'Emily Wang',
role: 'CTO',
rating: 5,
avatar: 'https://i.pravatar.cc/150?u=a04258114e29026302d',
content:
'Scalable, reliable, and beautiful. Highly recommended for any modern web project.',
},
{
name: 'David Smith',
role: 'Marketing Lead',
rating: 5,
avatar: 'https://i.pravatar.cc/150?u=a042581f4e29026024d',
content:
'Our conversion rates increased by 15% after switching to this UI system.',
},
{
name: 'Jessica Lee',
role: 'Indie Hacker',
rating: 4,
avatar: 'https://i.pravatar.cc/150?u=a04258a2462d826712d',
content:
'Documentation is top-notch. I was able to build my MVP in a single weekend.',
},
]
Finite Loops
To loop the marquee a finite number of times, set the loopCount prop on
Marquee.Root. Alternatively, use the onLoopComplete and onComplete
callbacks to track the number of completed loops or when the animation fully
finishes.
<Marquee.Root
loopCount={3}
onLoopComplete={() => {
/* handle loop completion */
}}
onComplete={() => {
/* handle animation end */
}}
>
{/* Marquee.Item elements */}
</Marquee.Root>CSS Variables
The marquee component exposes CSS variables that can be used to customize its behavior and appearance.
<Marquee.Root
css={{
'--marquee-duration': '30s',
'--marquee-delay': '0s',
'--marquee-loop-count': 'infinite',
'--marquee-edge-color': 'colors.bg',
'--marquee-edge-size': '20%',
}}
>
{/* ... */}
</Marquee.Root>| Variable | Description | Default |
|---|---|---|
--marquee-duration | Animation duration | Computed |
--marquee-delay | Animation delay before starting | 0s |
--marquee-loop-count | Number of animation iterations | infinite |
--marquee-edge-color | Color for the edge gradient overlay | colors.bg |
--marquee-edge-size | Size of the edge gradient | 20% |
Props
| Prop | Default | Type |
|---|---|---|
autoFill | false | booleanWhether to automatically duplicate content to fill the container. |
defaultPaused | false | booleanWhether the marquee is paused by default. |
delay | '0' | numberThe delay before the animation starts (in seconds). |
loopCount | '0' | numberThe number of times to loop the animation (0 = infinite). |
pauseOnInteraction | false | booleanWhether to pause the marquee on user interaction (hover, focus). |
reverse | false | booleanWhether to reverse the animation direction. |
side | '\'start\'' | SideThe side/direction the marquee scrolls towards. |
spacing | '\'1rem\'' | stringThe spacing between marquee items. |
speed | '50' | numberThe speed of the marquee animation in pixels per second. |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
ids | Partial<{ root: string; viewport: string; content: (index: number) => string }>The ids of the elements in the marquee. Useful for composition. | |
onComplete | () => voidFunction called when the marquee completes all loops and stops. Only fires for finite loops (loopCount > 0). | |
onLoopComplete | () => voidFunction called when the marquee completes one loop iteration. | |
onPauseChange | (details: PauseStatusDetails) => voidFunction called when the pause status changes. | |
paused | booleanWhether the marquee is paused. | |
translations | IntlTranslationsThe localized messages to use. |