Marquee
An infinitely scrolling strip for logos and highlights — CSS-driven, pausable, gradient-masked.
React
TypeScript
Vitest
Vite
Next.js
CVA
pnpm
"use client";
import { Marquee, Text, Box } from "astralis-ui";
const stack = ["React", "TypeScript", "Vitest", "Vite", "Next.js", "CVA", "pnpm"];
export function MarqueeDemo() {
return (
<Box w="full" maxW="md">
<Marquee speed={40} gap="0.75rem" pauseOnHover gradient>
{stack.map((name) => (
<Marquee.Item key={name}>
<Box border="normal" borderColor="subtle" bg="panel" px="4" py="2" rounded="full">
<Text as="span" size="sm">{name}</Text>
</Box>
</Marquee.Item>
))}
</Marquee>
</Box>
);
}Import#
import { Marquee } from "astralis-ui";
// Marquee.ItemUsage#
Children are duplicated once (the clone is aria-hidden) for a seamless
loop; the animation is pure CSS keyframes, so it costs nothing at runtime.
gradient masks the edges into the background.
Opposing rows#
Semantic tokens
Runtime theming
Dark mode
Responsive props
Compound components
Accent channel
Zero build step
Typed styles
"use client";
import { Marquee, Text, Box, VStack } from "astralis-ui";
const row1 = ["Semantic tokens", "Runtime theming", "Dark mode", "Responsive props"];
const row2 = ["Compound components", "Accent channel", "Zero build step", "Typed styles"];
export function MarqueeReverse() {
return (
/* Two rows in opposite directions — the classic logo-wall move. */
<VStack gap="3" w="full" maxW="md">
<Marquee speed={35} gap="0.75rem" gradient>
{row1.map((label) => (
<Marquee.Item key={label}>
<Box bg="brand-subtle" px="4" py="1.5" rounded="full">
<Text as="span" size="xs">{label}</Text>
</Box>
</Marquee.Item>
))}
</Marquee>
<Marquee speed={35} gap="0.75rem" gradient reverse>
{row2.map((label) => (
<Marquee.Item key={label}>
<Box bg="purple-subtle" px="4" py="1.5" rounded="full">
<Text as="span" size="xs">{label}</Text>
</Box>
</Marquee.Item>
))}
</Marquee>
</VStack>
);
}Props#
| Prop | Type | Default | Description |
|---|---|---|---|
direction | "left" | "right" | "up" | "down" | "left" | Scroll axis and direction. |
speed | number | 50 | Pixels per second. |
gap | CSS length | "1rem" | Space between items (and the loop seam). |
pauseOnHover / pauseOnFocus | boolean | false | Pause for pointer or keyboard users. |
reverse | boolean | false | Flip the direction. |
gradient / gradientColor / gradientWidth | boolean / color / length | false / surface / "10%" | Edge fade mask. |
loopCount | number | 0 | Loops before stopping (0 = infinite). |
Accessibility#
The duplicated track is aria-hidden, and pauseOnFocus lets keyboard
users freeze the motion — turn it on when items are interactive.