Price Ticker
Preview: Cards
Price tick: symbol, rolling price, signed change with arrow and color, optional sparkline. Change is never color-only.
Import
import { StatTicker } from '@marbleui/ui'Props
<StatTicker>
| Prop | Type | Default | Description |
|---|---|---|---|
| quote *required | Quote | — | |
| className | string | — | |
| variant | 'card' | 'inline' | 'card' |
Usage notes
Compact price quote: symbol, price, signed percentage change and an optional sparkline. For a KPI tile use Stat.
<StatTicker quote={{ symbol: 'ACME', name: 'Acme Corp', price: 182.4, change: 1.24, history: [170, 175, 178, 182] }} />
<Marquee aria-label="Market tape">
{quotes.map((q) => <StatTicker key={q.symbol} variant="inline" quote={q} />)}
</Marquee>
changeis a percentage (1.24shows “+1.24%”), not an amount. The arrow comes with a hidden “up” or “down” word, so direction isn’t color-only.priceis formatted withcurrency(defaultUSD) and its digits roll when it changes. Screen readers get the value, but updates aren’t announced.variant="card"(default) addsnameand, whenhistoryis set, a sparkline.inlinefits aMarqueetape.- The sparkline’s color and its rising/falling label both follow the sign of
change, so they always agree with the arrow; cover the same period withhistoryso the line’s shape matches.
Example source · show· hide
import { useEffect, useState } from 'react'
import { Marquee } from '../motion-marquee'
import { StatTicker, type Quote } from './stat-ticker'
const base: Quote[] = [
{ symbol: 'ACME', name: 'Acme Corp', price: 182.4, change: 1.24, history: [170, 172, 171, 175, 178, 177, 182] },
{ symbol: 'GLBX', name: 'Globex', price: 48.12, change: -0.86, history: [52, 51, 50, 50.5, 49, 48.6, 48.1] },
{ symbol: 'INIT', name: 'Initech', price: 9.87, change: 3.1, history: [8.9, 9.1, 9.0, 9.4, 9.5, 9.7, 9.87] },
]
function Live() {
const [qs, setQs] = useState(base)
useEffect(() => { const t = setInterval(() => setQs((s) => s.map((q) => { const d = (Math.random() - 0.48) * q.price * 0.01; return { ...q, price: +(q.price + d).toFixed(2), change: +(q.change + (d / q.price) * 100).toFixed(2) } })), 1800); return () => clearInterval(t) }, [])
return <div className="flex w-80 flex-col gap-2">{qs.map((q) => <StatTicker key={q.symbol} quote={q} />)}</div>
}
export const styles = {
Cards: Live,
Tape: () => <Marquee aria-label="Market tape" className="w-[36rem] rounded-lg border border-border bg-surface py-2" gap="2rem">{base.concat(base).map((q, i) => <StatTicker key={i} variant="inline" quote={q} />)}</Marquee>,
}Source: packages/ui/src/stat-ticker/stat-ticker.tsx
Catalog
- Category
- data-display
- Priority
- Extra
- Primitive
- custom