How to Build a StockTicker Marquee with HTML, CSS & JavaScript
Overview
Create a lightweight, accessible, and responsive scrolling stock ticker that fetches real-time or simulated prices and displays symbol, price, change, and change color. This guide assumes you’ll fetch data via an API or WebSocket; if not available, it uses simulated updates.
Files
- index.html
- styles.css
- app.js
HTML (structure)
html
<!doctype html> <html lang=“en”> <head> <meta charset=“utf-8” /> <meta name=“viewport” content=“width=device-width,initial-scale=1” /> <title>StockTicker Marquee</title> <link rel=“stylesheet” href=“styles.css” /> </head> <body> <div class=“ticker” role=“region” aria-label=“Stock ticker”> <div class=“tickertrack” id=“tickerTrack” aria-live=“polite”></div> </div> <script src=“app.js”></script> </body> </html>
CSS (styles.css)
css
:root{ –bg:#0b1220; –text:#e6eef8; –up:#28a745; –down:#d93636; –muted:#95a3b8; –height:48px; –gap:32px; } *{box-sizing:border-box} body{margin:0;font-family:Inter,system-ui,-apple-system,Segoe UI,Roboto,“Helvetica Neue”,Arial;background:var(–bg);color:var(–text);display:flex;align-items:center;justify-content:center;height:100vh} .ticker{ width:100%; max-width:1100px; background:linear-gradient(90deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01)); border-radius:8px; padding:6px 12px; overflow:hidden; height:var(–height); display:flex; align-items:center; } .tickertrack{ display:flex; gap:var(–gap); align-items:center; will-change:transform; white-space:nowrap; animation:scroll 25s linear infinite; } .tickeritem{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:6px; background:transparent; color:var(–text); font-size:14px; } .tickersymbol{font-weight:700} .tickerprice{min-width:70px;text-align:right;font-variant-numeric:tabular-nums} .tickerchange{padding-left:8px;font-variant-numeric:tabular-nums} .tickerup{color:var(–up)} .tickerdown{color:var(–down)} .tickermuted{color:var(–muted);font-weight:600} @keyframes scroll{ 0%{transform:translateX(0)} 100%{transform:translateX(-50%)} } /* Pause on hover for accessibility */ .ticker:hover .tickertrack, .ticker:focus-within .tickertrack{ animation-play-state:paused; }
JavaScript (app.js)
js
// Config const symbols = [‘AAPL’,‘MSFT’,‘GOOGL’,‘AMZN’,‘TSLA’,‘NVDA’,‘META’,‘BABA’]; const track = document.getElementById(‘tickerTrack’); const updateInterval = 3000; // ms for simulated updates // Utility: format price & change const fmt = num => Number(num).toLocaleString(undefined, {minimumFractionDigits:2, maximumFractionDigits:2}); const sign = n => (n>0?’+’:(n<0?’-’:“)); // Create item element function createItem(sym, price, change){ const item = document.createElement(‘div’); item.className = ‘tickeritem’; item.innerHTML =</span><span class="token template-string" style="color: rgb(163, 21, 21);"> </span><span class="token template-string" style="color: rgb(163, 21, 21);"> <span class="ticker__symbol"></span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">${</span><span class="token template-string interpolation">sym</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">}</span><span class="token template-string" style="color: rgb(163, 21, 21);"></span> </span><span class="token template-string" style="color: rgb(163, 21, 21);"> <span class="ticker__price">$</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">${</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">fmt</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">(</span><span class="token template-string interpolation">price</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">)</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">}</span><span class="token template-string" style="color: rgb(163, 21, 21);"></span> </span><span class="token template-string" style="color: rgb(163, 21, 21);"> <span class="ticker__change </span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">${</span><span class="token template-string interpolation">change</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">></span><span class="token template-string interpolation" style="color: rgb(54, 172, 170);">0</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">?</span><span class="token template-string interpolation" style="color: rgb(163, 21, 21);">'ticker__up'</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">:</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">(</span><span class="token template-string interpolation">change</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);"><</span><span class="token template-string interpolation" style="color: rgb(54, 172, 170);">0</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">?</span><span class="token template-string interpolation" style="color: rgb(163, 21, 21);">'ticker__down'</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">:</span><span class="token template-string interpolation" style="color: rgb(163, 21, 21);">'ticker__muted'</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">)</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">}</span><span class="token template-string" style="color: rgb(163, 21, 21);">"> </span><span class="token template-string" style="color: rgb(163, 21, 21);"> </span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">${</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">sign</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">(</span><span class="token template-string interpolation">change</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">)</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">}</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">${</span><span class="token template-string interpolation">Math</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">.</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">abs</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">(</span><span class="token template-string interpolation">change</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">)</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">.</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">toFixed</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">(</span><span class="token template-string interpolation" style="color: rgb(54, 172, 170);">2</span><span class="token template-string interpolation" style="color: rgb(57, 58, 52);">)</span><span class="token template-string interpolation interpolation-punctuation" style="color: rgb(57, 58, 52);">}</span><span class="token template-string" style="color: rgb(163, 21, 21);"> </span><span class="token template-string" style="color: rgb(163, 21, 21);"> </span></span><span class="token template-string template-punctuation" style="color: rgb(163, 21, 21);">; return item; } // Simulate initial prices const state = {}; symbols.forEach(s=>{ state[s] = {price: Math.random()150+50}; }); // Render items twice for seamless loop function render(){ track.innerHTML = ”; const fragment = document.createDocumentFragment(); symbols.forEach(s=>{ fragment.appendChild(createItem(s, state[s].price, state[s].change || 0)); }); // duplicate const frag2 = fragment.cloneNode(true); track.appendChild(fragment); track.appendChild(frag2); } render(); // Simulate updates (replace with real API/WebSocket) function randomWalk(){ symbols.forEach(s=>{ const p = state[s].price; const delta = (Math.random()-0.48) (p 0.01); // ~1% moves const newP = Math.max(0.01, p + delta); state[s].change = newP - p; state[s].price = newP; }); render(); } // Example of integrating a real API (pseudo): // fetch(‘/api/prices’).then(r=>r.json()).then(data => { / update state and render */ }); // Start updates setInterval(randomWalk, updateInterval);
Accessibility & Performance Notes
- Use aria-live or role=region to announce updates; pause animation on hover/focus.
- For real-time data, prefer WebSocket for low-latency updates; fall back to polling.
- Duplicate the track contents for smooth infinite scrolling, or use CSS scroll snapping for different effects.
- Keep DOM updates minimal: update text nodes rather than reconstructing whole DOM for high-frequency updates.
Deployment tips
- Host only necessary assets; minify CSS/JS.
- Cache static assets and use rate limits for API calls.
- If using third-party market data, check usage limits and display disclaimers if required.
If you want, I can convert this into a single-file example or show a WebSocket integration example.
Leave a Reply