Marquee
A continuous scrolling component for displaying content in a seamless loop.
Features
- Smooth GPU-accelerated animations with seamless looping
- Horizontal and vertical scrolling with RTL support
- Auto-fill mode to duplicate content
- Customizable speed and spacing
- Pause on hover/focus with keyboard support
- Programmatic control and finite loops
Anatomy
To set up the marquee correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Examples
Learn how to use the Marquee component in your project. Let's take a look at the most basic example:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Basic = () => (
<Marquee.Root>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
import { For } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Basic = () => (
<Marquee.Root>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<template>
<Marquee.Root>
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<Marquee.Root>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
Auto Fill
Use the autoFill prop to automatically duplicate content to fill the viewport. The spacing prop controls the gap
between duplicated content instances:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry']
export const AutoFill = () => (
<Marquee.Root autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
import { Marquee } from '@ark-ui/solid/marquee'
import { For } from 'solid-js'
const items = ['Apple', 'Banana', 'Cherry']
export const AutoFill = () => (
<Marquee.Root autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry']
</script>
<template>
<Marquee.Root auto-fill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry']
</script>
<Marquee.Root autoFill spacing="2rem">
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
Reverse Direction
Set the reverse prop to reverse the scroll direction:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Reverse = () => (
<Marquee.Root reverse>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
import { For } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Reverse = () => (
<Marquee.Root reverse>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<template>
<Marquee.Root reverse>
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<Marquee.Root reverse>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
Vertical Orientation
Set side="bottom" (or side="top") to create a vertical marquee:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Vertical = () => (
<Marquee.Root side="bottom" style={{ height: '300px' }}>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '1rem 0' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
import { For } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Vertical = () => (
<Marquee.Root side="bottom" style={{ height: '300px' }}>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '1rem 0' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<template>
<Marquee.Root side="bottom" style="height: 300px">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 1rem 0">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<Marquee.Root side="bottom" style="height: 300px">
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 1rem 0">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
Custom Speed
Control the animation speed using the speed prop, which accepts values in pixels per second:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Speed = () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
<div>
<h3>Slow (25px/s)</h3>
<Marquee.Root speed={25}>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Normal (50px/s)</h3>
<Marquee.Root speed={50}>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Fast (100px/s)</h3>
<Marquee.Root speed={100}>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
</div>
)
import { For } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const Speed = () => (
<div style={{ display: 'flex', 'flex-direction': 'column', gap: '2rem' }}>
<div>
<h3>Slow (25px/s)</h3>
<Marquee.Root speed={25}>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Normal (50px/s)</h3>
<Marquee.Root speed={50}>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Fast (100px/s)</h3>
<Marquee.Root speed={100}>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
</div>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 2rem">
<div>
<h3>Slow (25px/s)</h3>
<Marquee.Root :speed="25">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Normal (50px/s)</h3>
<Marquee.Root :speed="50">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Fast (100px/s)</h3>
<Marquee.Root :speed="100">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
</div>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<div style="display: flex; flex-direction: column; gap: 2rem">
<div>
<h3>Slow (25px/s)</h3>
<Marquee.Root speed={25}>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Normal (50px/s)</h3>
<Marquee.Root speed={50}>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
<div>
<h3>Fast (100px/s)</h3>
<Marquee.Root speed={100}>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</div>
</div>
Pause on Interaction
Enable pauseOnInteraction to pause the marquee when users hover or focus on it, improving accessibility:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const PauseOnInteraction = () => (
<Marquee.Root pauseOnInteraction>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
import { For } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const PauseOnInteraction = () => (
<Marquee.Root pauseOnInteraction>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<template>
<Marquee.Root pause-on-interaction>
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<Marquee.Root pauseOnInteraction>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
Programmatic Control
Use the useMarquee hook with Marquee.RootProvider to access the marquee API and control playback programmatically:
import { Marquee, useMarquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const ProgrammaticControl = () => {
const marquee = useMarquee()
return (
<>
<Marquee.RootProvider value={marquee}>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.RootProvider>
<div style={{ marginTop: '1rem', display: 'flex', gap: '0.5rem' }}>
<button onClick={() => marquee.pause()}>Pause</button>
<button onClick={() => marquee.resume()}>Resume</button>
</div>
</>
)
}
import { For } from 'solid-js'
import { Marquee, useMarquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const ProgrammaticControl = () => {
const marquee = useMarquee()
return (
<>
<Marquee.RootProvider value={marquee}>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.RootProvider>
<div style={{ 'margin-top': '1rem', display: 'flex', gap: '0.5rem' }}>
<button onClick={() => marquee().pause()}>Pause</button>
<button onClick={() => marquee().resume()}>Resume</button>
</div>
</>
)
}
<script setup lang="ts">
import { Marquee, useMarquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
const marquee = useMarquee({})
</script>
<template>
<Marquee.RootProvider :value="marquee">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.RootProvider>
<div style="margin-top: 1rem; display: flex; gap: 0.5rem">
<button @click="marquee.pause()">Pause</button>
<button @click="marquee.resume()">Resume</button>
</div>
</template>
<script lang="ts">
import { Marquee, useMarquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
const id = $props.id()
const marquee = useMarquee(() => ({ id }))
</script>
<Marquee.RootProvider value={marquee}>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.RootProvider>
<div style="margin-top: 1rem; display: flex; gap: 0.5rem">
<button onclick={() => marquee().pause()}>Pause</button>
<button onclick={() => marquee().resume()}>Resume</button>
</div>
If you're using the
Marquee.RootProvidercomponent, you don't need to use theMarquee.Rootcomponent.
Finite Loops
Set the loopCount prop to run the marquee a specific number of times. Use onLoopComplete to track each loop
iteration and onComplete to know when all loops finish:
import { useState } from 'react'
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const FiniteLoops = () => {
const [loopCount, setLoopCount] = useState(0)
const [completedCount, setCompletedCount] = useState(0)
return (
<>
<Marquee.Root
loopCount={3}
onLoopComplete={() => setLoopCount((prev) => prev + 1)}
onComplete={() => setCompletedCount((prev) => prev + 1)}
>
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
<div style={{ marginTop: '1rem' }}>
<p>Loop completed: {loopCount} times</p>
<p>Animation completed: {completedCount} times</p>
</div>
</>
)
}
import { For, createSignal } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const FiniteLoops = () => {
const [loopCount, setLoopCount] = createSignal(0)
const [completedCount, setCompletedCount] = createSignal(0)
return (
<>
<Marquee.Root
loopCount={3}
onLoopComplete={() => setLoopCount((prev) => prev + 1)}
onComplete={() => setCompletedCount((prev) => prev + 1)}
>
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
<div style={{ 'margin-top': '1rem' }}>
<p>Loop completed: {loopCount()} times</p>
<p>Animation completed: {completedCount()} times</p>
</div>
</>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
const loopCount = ref(0)
const completedCount = ref(0)
</script>
<template>
<Marquee.Root :loop-count="3" @loop-complete="loopCount++" @complete="completedCount++">
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
<div style="margin-top: 1rem">
<p>Loop completed: {{ loopCount }} times</p>
<p>Animation completed: {{ completedCount }} times</p>
</div>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
let loopCount = $state(0)
let completedCount = $state(0)
</script>
<Marquee.Root
loopCount={3}
onLoopComplete={() => loopCount++}
onComplete={() => completedCount++}
>
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
</Marquee.Root>
<div style="margin-top: 1rem">
<p>Loop completed: {loopCount} times</p>
<p>Animation completed: {completedCount} times</p>
</div>
Edge Gradients
Add Marquee.Edge components to create fade effects at the start and end of the scrolling area:
import { Marquee } from '@ark-ui/react/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const WithEdges = () => (
<Marquee.Root>
<Marquee.Edge side="start" />
<Marquee.Viewport>
<Marquee.Content>
{items.map((item, i) => (
<Marquee.Item key={i} style={{ padding: '0 2rem' }}>
{item}
</Marquee.Item>
))}
</Marquee.Content>
</Marquee.Viewport>
<Marquee.Edge side="end" />
</Marquee.Root>
)
import { For } from 'solid-js'
import { Marquee } from '@ark-ui/solid/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
export const WithEdges = () => (
<Marquee.Root>
<Marquee.Edge side="start" />
<Marquee.Viewport>
<Marquee.Content>
<For each={items}>{(item) => <Marquee.Item style={{ padding: '0 2rem' }}>{item}</Marquee.Item>}</For>
</Marquee.Content>
</Marquee.Viewport>
<Marquee.Edge side="end" />
</Marquee.Root>
)
<script setup lang="ts">
import { Marquee } from '@ark-ui/vue/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<template>
<Marquee.Root>
<Marquee.Edge side="start" />
<Marquee.Viewport>
<Marquee.Content>
<Marquee.Item v-for="item in items" :key="item" style="padding: 0 2rem">{{ item }}</Marquee.Item>
</Marquee.Content>
</Marquee.Viewport>
<Marquee.Edge side="end" />
</Marquee.Root>
</template>
<script lang="ts">
import { Marquee } from '@ark-ui/svelte/marquee'
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape']
</script>
<Marquee.Root>
<Marquee.Edge side="start" />
<Marquee.Viewport>
<Marquee.Content>
{#each items as item}
<Marquee.Item style="padding: 0 2rem">{item}</Marquee.Item>
{/each}
</Marquee.Content>
</Marquee.Viewport>
<Marquee.Edge side="end" />
</Marquee.Root>
Guides
Styling Requirements
The Marquee component requires CSS keyframe animations to function properly. You'll need to define animations for both horizontal and vertical scrolling:
@keyframes marqueeX {
from {
transform: translateX(0);
}
to {
transform: translateX(var(--marquee-translate));
}
}
@keyframes marqueeY {
from {
transform: translateY(0);
}
to {
transform: translateY(var(--marquee-translate));
}
}
The component automatically applies the appropriate animation (marqueeX or marqueeY) based on the scroll direction
and uses the --marquee-translate CSS variable for seamless looping.
You can target specific parts of the marquee using data-part attributes for custom styling:
[data-part="root"]- The root container[data-part="viewport"]- The scrolling viewport[data-part="content"]- The content wrapper (receives animation)[data-part="item"]- Individual marquee items[data-part="edge"]- Edge gradient overlays
Best Practices
- Enable pause-on-interaction: Use
pauseOnInteractionto allow users to pause animations on hover or focus, improving accessibility and readability - Use descriptive labels: Provide meaningful
aria-labelvalues that describe the marquee content (e.g., "Partner logos", "Latest announcements") - Avoid for critical information: Don't use marquees for essential content that users must read, as continuously moving text can be difficult to process. Consider static displays for important information
API Reference
Props
Context
These are the properties available when using Marquee.Context, useMarqueeContext hook or useMarquee hook.
API
| Property | Type |
|---|---|
paused | booleanWhether the marquee is currently paused. |
orientation | "horizontal" | "vertical"The current orientation of the marquee. |
side | SideThe current side/direction of the marquee. |
multiplier | numberThe multiplier for auto-fill. Indicates how many times to duplicate content. When autoFill is enabled and content is smaller than container, this returns the number of additional copies needed. Otherwise returns 1. |
contentCount | numberThe total number of content elements to render (original + clones). Use this value when rendering your content in a loop. |
pause | VoidFunctionPause the marquee animation. |
resume | VoidFunctionResume the marquee animation. |
togglePause | VoidFunctionToggle the pause state. |
restart | VoidFunctionRestart the marquee animation from the beginning. |
Accessibility
The Marquee component is built with accessibility in mind:
- Uses appropriate ARIA attributes:
role="region"andaria-roledescription="marquee" - Cloned content for seamless looping is marked with
aria-hidden="true"to avoid confusion for screen readers - Automatically respects user motion preferences via
prefers-reduced-motion - Supports keyboard interaction when
pauseOnInteractionis enabled - Allows users to pause animations on hover or focus for better readability