Gallery✨ Premium

Live Ticker

A metrics strip that scrolls forever by recycling its items, can be dragged by hand with inertia and updates with a green or red flash.

MarqueeLive DataDOM RecyclingFinanceSaaS

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Gallery has 44 effects, including 6 free. Explore the category →

3 usage examples

Today's conditions at the top of a ski resort website — Live Ticker example 1

① Today's conditions at the top of a ski resort website

WhenAt the very top of a resort home page, above the navigation: a dark 34 px band introduced by “Today” runs fresh snow, open runs, lifts, summit temperature, wind and avalanche risk.
WhyThis is what people come for before heading out: it stays visible on every page without taking room from the content, and stops on hover so a figure can be read.
Settingsdata-ltk-speed="40"; 34 px root laid out in a row (flex-direction: row) with the “Today” label, the band and the Pause button; items without data-delta; labels #93c5fd, white values on #0b1a2b.
Free parking spaces on a small town's entrance sign — Live Ticker example 2

② Free parking spaces on a small town's entrance sign

WhenA large sign at the entrance to the town centre shows rates, Saturday notices and charging points; at the bottom, a blue “P Spaces” band runs the number of free spaces in each car park. When the counting system sends a new figure, the value changes with a green or red flash.
WhyDrivers read every car park in a few seconds without searching a table; the flash points to the car park that has just filled up or freed up.
Settingsdata-ltk-speed="70", data-ltk-unit="", data-ltk-decimals="0" (change without a unit); 84 px band, 27 px values; each item has a short data-label (P1…P4). The scene calls root.ltkTicker.push({label: 'P2', value: '35', delta: -3}) every 1.4 s to simulate the counting.
Release log you drag to go back in time — Live Ticker example 3

③ Release log you drag to go back in time

WhenIn a tech team's internal dashboard, below the service status: a “Release log” card scrolls the latest versions (time, service, released or rolled back). You grab the band to go back.
WhyThe log fits on one line instead of a table; dragging both ways finds a recent release without leaving the page.
Settingsdata-ltk-speed="28"; items stacked (time, version, status), without data-delta; white background, #6366f1 labels. For the capture, the scene sends a rightward drag (pointer events) to the real code every 3 s.

How it works

You write your items inside .ltk-track: one .ltk-item per metric, with a .ltk-label, a .ltk-value and, if you want a change badge, the data-delta attribute (the script builds the green, red or neutral “▲ +4.20%” pill). The script adds the separators, then hidden copies of the list until the track covers the band width plus twice the widest item: the band stays full even in a 1,700 px area.

The track moves left at 60 px/s (based on elapsed time). As soon as an item has fully left on the left, it is moved to the end of the track and the offset is corrected by its width, measured at that moment: no jump, even if a value changed length in between. Dragged to the right, the track does the opposite and brings the last item back to the front.

Hovering the band, keyboard focus inside the band or the Pause button stops the scrolling. You can grab the band with a mouse or a finger; on release it keeps the gesture's momentum, then returns to its speed. Each root exposes root.ltkTicker: push({label, value, delta}) updates every copy of a metric with a 0.55 s flash (or adds it if missing), pause(), play() and setSpeed(px). The bundled frame (header and three cards) is plain HTML dressing, with no script.

Accessibility

  • No looping announcements: the band has the marquee role and an aria-label, without aria-live; updates are not read out automatically. Only your original items are read: copies carry aria-hidden="true", their links tabindex="-1".
  • Pause: hover, keyboard focus on a link in the band or the Pause button (aria-pressed) stop the scrolling (WCAG 2.2.2).
  • Reduced motion: under prefers-reduced-motion: reduce, no copies, no motion, no flash; the track becomes a list you scroll with a finger, the wheel or the keyboard (tabindex="0" when it overflows). push() still updates the values.
  • Links: a drag longer than 5 px does not open the link under the pointer; a plain click does. touch-action: pan-y lets the page scroll under a finger.

Browser compatibility

Pointer Events with setPointerCapture, IntersectionObserver and ResizeObserver (feature-tested), mask-image for the edge fade. Measured on 2026-11-08 in Chromium, Firefox and Playwright's WebKit: 60 px/s, stop on hover, focus and button, two independent copies, full band at 1,700 px, reduced motion, finger drag at 390 px.

Chrome 64+✓ Full (measured)
Firefox 69+✓ Full (measured)
Safari 13.1+✓ Measured in WebKit, not in a real Safari
Edge 79+✓ Full (same engine as Chrome)
Safari iOS 13.4+✓ Not checked on a device
Chrome Android 64+✓ Finger drag measured in emulation

Without JavaScript, the list shows still, with no separators or change pills. Without mask-image, two gradients laid on the edges take over.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0834-root" data-ltk-speed="60" data-ltk-unit="%" data-ltk-decimals="2">
  <div class="ltk-demo-panel">
    <div class="ltk-panel-header">
      <span class="ltk-panel-title">…</span>
      <button class="ltk-btn-pause" type="button" aria-label="…" aria-pressed="false">⏸</button>
    </div>
    <div class="ltk-root" role="marquee" aria-label="…">
      <div class="ltk-track">
        <span class="ltk-item" data-delta="4.2"><span class="ltk-label">…</span><span class="ltk-value">…</span></span>
      </div>
    </div>
    <div class="ltk-panel-stats">
      <div class="ltk-stat-card">…</div>
    </div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Items (HTML — .ltk-item inside .ltk-track) 8 made-up shop metrics One .ltk-label and one .ltk-value per item; a link or an icon can go inside.
Change (HTML — data-delta on .ltk-item) Absent: no pill Positive number (green ▲), negative (red ▼) or 0 (grey —).
Unit and decimals (HTML — data-ltk-unit, data-ltk-decimals on the root) “%” and 2 E.g. data-ltk-unit=" pt" data-ltk-decimals="0" shows “▲ +2 pt”.
Speed (HTML — data-ltk-speed) 60 (px/s) From 0 to 600; change it later with root.ltkTicker.setSpeed(px).
Update (JS — root.ltkTicker.push({label, value, delta})) No automatic update Finds the item by its data-label (taken from the label text if missing), changes the value and the pill with a flash; adds the item if it is new.
Dressing (HTML — .ltk-demo-panel, .ltk-panel-header, .ltk-panel-stats) “Shop · Today” header and three cards Purely decorative: remove it to keep only .ltk-root and the Pause button in the root.
Colors (CSS — .ltk-label, .ltk-value, .ltk-delta--up / --down) #9696aa, #d4d4d8, #4ade80 / #f87171 Label, value and pill colors; band background on .ltk-root (#0d0d14).

FAQ

No: the demo shows made-up shop metrics and changes nothing on its own. Values come from your HTML and your push() calls, for instance after a request to your own server.
Get the root (document.querySelector('.fx-0834-root')) and, in your setInterval, call root.ltkTicker.push({label: 'Orders', value: '318', delta: 1.9}). The label must match the data-label or the .ltk-label text.
No. At build time and on every width change, the script adds hidden copies until it covers the band width plus twice the widest item; measured gap-free at 1,700 px.