Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/ascii-marquee.jsonUsage
import { AsciiMarquee } from "@/components/asciicn/ascii-marquee";
const quotes = [
{ label: "GLYF", value: "182.40", change: 2.41 },
{ label: "BRLL", value: "41.06", change: -0.87 },
];
export function Ticker() {
return <AsciiMarquee label="MARKETS" status="LIVE" items={quotes} />;
}An item is a string or a quote. A quote draws its label in bold, its value after it, and its change as ▲ or ▼ with the percentage, in upColor or downColor. A glyph bullet sits between items.
The row repeats the items end to end and moves by exactly one copy's width before it loops, so the seam never shows. With motion="step" it moves one glyph cell at a time, like an LED board; smooth glides. speed is in characters per second either way. secondRow adds a row under the first, behind a tee rule, moving the other way.
Examples
Departure board
Two rows of plain strings in a double frame, tinted orange by the parent's text colour, with larger 20 px cells.
Announcement strip
frame="none" and motion="smooth" for a quiet line of release notes at the top of a page.
Props
| Prop | Type | Default |
|---|---|---|
| items What scrolls past. A quote is { label, value?, change? }, with change in percent. | Type: readonly (string | AsciiMarqueeQuote)[] | Default – |
| secondRow A second row under the first, scrolling the other way. | Type: readonly (string | AsciiMarqueeQuote)[] | Default – |
| speed Characters per second. | Type: number | Default 8 |
| direction Which way the first row moves. | Type: "left" | "right" | Default "left" |
| motion Move one glyph cell at a time, or glide. | Type: "step" | "smooth" | Default "step" |
| pauseOnHover Hold still while the pointer is over it. | Type: boolean | Default true |
| frame Box-drawing set for the frame, or none. | Type: "light" | "heavy" | "double" | "rounded" | "ascii" | "none" | Default "light" |
| label A label set into the top rule. Also names the ticker for screen readers. | Type: string | Default – |
| status A label at the right end of the top rule, such as LIVE. | Type: string | Default – |
| separator The glyph between items. | Type: string | Default "◆" |
| cell Glyph cell height in CSS pixels. | Type: number | Default 16 |
| frameColor Colour of the frame and the status label. | Type: AsciiColor | Default "grey" |
| upColor Colour of rising changes. | Type: AsciiColor | Default "green" |
| downColor Colour of falling changes. | Type: AsciiColor | Default "red" |
Other props pass through to the root div.
Notes
- Screen readers get each item once, as a visually hidden list inside an element with
role="marquee". The moving copies and the frame arearia-hidden, and changes read as "up 2.41%" rather than as arrow glyphs. - The motion is a CSS animation on a transform, so it costs no JavaScript per frame. It pauses on hover, while the ticker is offscreen and while the tab is hidden.
- With reduced motion nothing moves. Each row becomes a horizontal scroller, so every item can still be read.
- The row measures one copy of its items after fonts load and again when it resizes, then adds copies until the track is wider than the row.
- The label and the items take the element's text colour; set
coloror a text class on the parent to tint them.