import { Marquee } from "@cerberus/react"The Marquee is an abracted API that combines multiple primitives into a single root component.
Use the spacing prop to control the gap between content instances.
Use the reverse prop to reverse the direction of the marquee.
Use the side prop to animate the marquee vertically. The options are top and bottom.
Use the speed prop to control the animation speed in pixels per second.
Use the edges prop to display stylized edges on the marquee. The options are both, start, and end.
Use the pauseOnInteraction prop to pause the marquee when users hover or focus on it, improving accessibility.
Access the combobox's state with ComboboxContext or the useComboboxContext hook—useful for displaying the selected value or building custom UI.
Note
Since combobox is an abstracted API, you'll need to build your own to obtain the context as we do in the example below.
To loop the marquee a finite number of times, set the loopCount prop on Marquee. Alternatively, use the onLoopComplete and onComplete callbacks to track the number of completed loops or when the animation fully finishes.
The marquee component exposes CSS variables that can be used to customize its behavior and appearance.
<Marquee
css={{
"--marquee-duration": "30s",
"--marquee-delay": "0s",
"--marquee-loop-count": "infinite",
"--marquee-edge-color": "colors.bg",
"--marquee-edge-size": "20%",
}}
>
{/* ... */}
</Marquee>| 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 | page.surface.initial |
--marquee-edge-size | Size of the edge gradient | 20% |
You can utilize the primitive components or the css prop to customize the Marquee.
| Component | Description |
|---|---|
| MarqueeRoot | The context provider for the Marquee family |
| MarqueeEdge | The stylistic edge of the Marquee |
| MarqueeViewport | The viewport container that holds the Marquee content |
| MarqueeContent | The content of the Marquee |
| MarqueeItem | The item to be displayed in the Marquee |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
autoFill | boolean | No | Whether to automatically duplicate content to fill the container. |
defaultPaused | boolean | No | Whether the marquee is paused by default. |
delay | number | No | The delay before the animation starts (in seconds). |
ids | Partial<{ root: string; viewport: string; content: (index: number) => string }> | No | The ids of the elements in the marquee. Useful for composition. |
loopCount | number | No | The number of times to loop the animation (0 = infinite). |
onComplete | () => void | No | Function called when the marquee completes all loops and stops. Only fires for finite loops (loopCount > 0). |
onLoopComplete | () => void | No | Function called when the marquee completes one loop iteration. |
onPauseChange | (details: PauseStatusDetails) => void | No | Function called when the pause status changes. |
paused | boolean | No | Whether the marquee is paused. |
pauseOnInteraction | boolean | No | Whether to pause the marquee on user interaction (hover, focus). |
reverse | boolean | No | Whether to reverse the animation direction. |
side | Side | No | The side/direction the marquee scrolls towards. |
spacing | string | No | The spacing between marquee items. |
speed | number | No | The speed of the marquee animation in pixels per second. |
translations | IntlTranslations | No | The localized messages to use. |
| Attribute | Value |
|---|---|
[data-scope] | marquee |
[data-part] | root |
[data-state] | "paused" | "idle" |
[data-orientation] | The orientation of the marquee |
[data-paused] | Present when paused |
| Variable | Description |
|---|---|
--marquee-duration | The marquee duration value for the Root |
--marquee-spacing | The marquee spacing value for the Root |
--marquee-delay | The marquee delay value for the Root |
--marquee-loop-count | The marquee loop count value for the Root |
--marquee-translate | The marquee translate value for the Root |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Attribute | Value |
|---|---|
[data-scope] | marquee |
[data-part] | |
[data-index] | The index of the item |
[data-orientation] | The orientation of the content |
[data-side] | |
[data-reverse] | |
[data-clone] |
| Prop | Type | Required | Description |
|---|---|---|---|
side | Side | Yes | The side where the edge gradient should appear. |
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Attribute | Value |
|---|---|
[data-scope] | marquee |
[data-part] | |
[data-side] | |
[data-orientation] | The orientation of the edge |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Attribute | Value |
|---|---|
[data-scope] | marquee |
[data-part] | |
[data-orientation] | The orientation of the viewport |
[data-side] |
| Prop | Type | Required | Description |
|---|---|---|---|
value | UseMarqueeReturn | Yes | |
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
The Marquee API is an Object containing the full family of components.
| Name | Description |
|---|---|
| Root | The context provider for the Marquee family |
| Edge | The stylistic edge of the Marquee |
| Viewport | The viewport container that holds the Marquee content |
| Content | The content of the Marquee |
| Item | The item to be displayed in the Marquee |
On this page
Loading...
Loading...
Loading...
Loading...
'use client'
import { Box, Square, Stack } from '@/styled-system/jsx'
import { Button, For, Marquee, Show, useMarquee } from '@cerberus/react'
import { socials } from './data'
import { Pause, Play } from '@carbon/icons-react'
export function StoreDemo() {
const marquee = useMarquee({
autoFill: true,
spacing: '5rem',
})
return (
<Stack gap="lg" w="full">
<Marquee.RootProvider value={marquee}>
<Marquee.Viewport>
<Marquee.Content>
<For each={socials}>
{(item) => (
<Marquee.Item key={item.label}>
<Square size="4rem" style={{ color: item.color }}>
<item.icon size="3rem" />
</Square>
</Marquee.Item>
)}
</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.RootProvider>
<Box ps="md">
<Show
when={marquee.paused}
fallback={
<Button onClick={marquee.pause} size="sm">
<Pause />
Pause
</Button>
}
>
<Button onClick={marquee.resume} size="sm" usage="outlined-subtle">
<Play />
Resume
</Button>
</Show>
</Box>
</Stack>
)
}
Loop completed: 0
Animation completed: 0
'use client'
import { Square, Stack } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { createSignal, ReactiveText } from '@cerberus/signals'
import { socials } from './data'
function finiteStore() {
const [loopCount, setLoopCount] = createSignal(0)
const [completedCount, setCompletedCount] = createSignal(0)
return { loopCount, setLoopCount, completedCount, setCompletedCount }
}
const store = finiteStore()
export function FiniteDemo() {
return (
<Stack gap="lg" px="md" w="full">
<Marquee
loopCount={3}
onLoopComplete={() => store.setLoopCount((prev) => prev + 1)}
onComplete={() => store.setCompletedCount((prev) => prev + 1)}
spacing="5rem"
>
<For each={socials}>
{(item) => (
<Marquee.Item key={item.label}>
<Square size="4rem" style={{ color: item.color }}>
<item.icon size="3rem" />
</Square>
</Marquee.Item>
)}
</For>
</Marquee>
<Stack m="4" textStyle="label-sm">
<p>
Loop completed: <ReactiveText data={store.loopCount} />
</p>
<p>
Animation completed: <ReactiveText data={store.completedCount} />
</p>
</Stack>
</Stack>
)
}
Slow (25pxps)
Normal (50pxps)
Fast (100pxps)
import { Square } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { socials } from './data'
export function BasicDemo() {
return (
<Marquee spacing="5rem">
<For each={socials}>
{(item) => (
<Marquee.Item key={item.label}>
<Square size="4rem" style={{ color: item.color }}>
<item.icon size="3rem" />
</Square>
</Marquee.Item>
)}
</For>
</Marquee>
)
}
import { Square } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { socials } from './data'
export function PauseDemo() {
return (
<Marquee pauseOnInteraction spacing="5rem">
<For each={socials}>
{(item) => (
<Marquee.Item key={item.label}>
<Square size="4rem" style={{ color: item.color }}>
<item.icon size="3rem" />
</Square>
</Marquee.Item>
)}
</For>
</Marquee>
)
}
import { HStack } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { items } from './data'
export function SpacingDemo() {
return (
<Marquee spacing="2rem">
<For each={items}>
{(item) => (
<Marquee.Item key={item.name}>
<HStack
bgColor="page.surface.100"
borderColor="page.border.initial"
gap="sm"
h="5rem"
layerStyle="outline.subtle"
px="md"
rounded="md"
shadow="md"
w="full"
>
{item.name} {item.logo}
</HStack>
</Marquee.Item>
)}
</For>
</Marquee>
)
}
import { Square } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { socials } from './data'
export function ReverseDemo() {
return (
<Marquee reverse spacing="5rem">
<For each={socials}>
{(item) => (
<Marquee.Item key={item.label}>
<Square size="4rem" style={{ color: item.color }}>
<item.icon size="3rem" />
</Square>
</Marquee.Item>
)}
</For>
</Marquee>
)
}
import { Center, HStack, Square, Stack } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { items, socials } from './data'
export function EdgesDemo() {
return (
<Stack gap="lg" w="full">
<Marquee edges={['both']} spacing="5rem">
<For each={socials}>
{(item) => (
<Marquee.Item key={item.label}>
<Square size="4rem" style={{ color: item.color }}>
<item.icon size="3rem" />
</Square>
</Marquee.Item>
)}
</For>
</Marquee>
<Marquee edges={['both']} side="bottom" spacing="2rem" maxH="15rem" px="lg">
<For each={items}>
{(item) => (
<Marquee.Item key={item.name}>
<Center
bgColor="page.surface.100"
borderColor="page.border.initial"
h="5rem"
layerStyle="outline.subtle"
rounded="md"
shadow="md"
>
<HStack gap="sm" h="full">
{item.name} {item.logo}
</HStack>
</Center>
</Marquee.Item>
)}
</For>
</Marquee>
</Stack>
)
}
import { Stack } from '@/styled-system/jsx'
import { For, Marquee, Text } from '@cerberus/react'
import { socials, speeds } from './data'
export function SpeedDemo() {
return (
<Stack gap="12" px="md" w="full">
<For each={speeds}>
{(speed) => (
<Stack key={speed.value} gap="4">
<Text textStyle="label-sm">{speed.label}</Text>
<Marquee speed={speed.value}>
<For each={socials}>
{(platform) => (
<Marquee.Item key={platform.label} px="2rem">
<platform.icon color={platform.color} size="3rem" />
</Marquee.Item>
)}
</For>
</Marquee>
</Stack>
)}
</For>
</Stack>
)
}
import { Center, HStack } from '@/styled-system/jsx'
import { For, Marquee } from '@cerberus/react'
import { items } from './data'
export function SideDemo() {
return (
<Marquee side="bottom" spacing="2rem" maxH="15rem" px="lg">
<For each={items}>
{(item) => (
<Marquee.Item key={item.name}>
<Center
bgColor="page.surface.100"
borderColor="page.border.initial"
h="5rem"
layerStyle="outline.subtle"
rounded="md"
shadow="md"
>
<HStack gap="sm" h="full">
{item.name} {item.logo}
</HStack>
</Center>
</Marquee.Item>
)}
</For>
</Marquee>
)
}