Marble UI
← Components

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>

PropTypeDefaultDescription
quote *requiredQuote—
classNamestring—
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>
  • change is a percentage (1.24 shows “+1.24%”), not an amount. The arrow comes with a hidden “up” or “down” word, so direction isn’t color-only.
  • price is formatted with currency (default USD) and its digits roll when it changes. Screen readers get the value, but updates aren’t announced.
  • variant="card" (default) adds name and, when history is set, a sparkline. inline fits a Marquee tape.
  • 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 with history so the line’s shape matches.
Example source · show
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