Lap Stopwatch with Splits — Free HTML CSS JS Snippet

Lap Stopwatch with Splits · Tools · Plain HTML, CSS & JS · Live preview

What's included

Features

Elapsed time computed from real Date.now() timestamps rather than a naively incremented counter
requestAnimationFrame-driven display updates decoupled from the underlying timing calculation
Accurate accumulation across multiple start/stop cycles with no drift or lost time
Lap recording that stores total elapsed time, with per-lap split times derived automatically
Most recent lap shown at the top of the list for easy at-a-glance tracking during use
MM: SS.ms display with centisecond precision and tabular-numeral formatting to avoid layout jitter
Lap button disabled while stopped, preventing laps from being recorded outside an active run
Full reset clears both the elapsed time and the recorded lap history

About this UI Snippet

Lap Stopwatch with Splits — Timestamp-Based Stopwatch and Lap Tracker

Screenshot of the Lap Stopwatch with Splits snippet rendered live

A stopwatch that simply adds a fixed amount to a counter on every tick will lose accuracy, because timers in the browser aren't perfectly regular — especially across pause/resume cycles. This snippet instead always derives elapsed time from real timestamps, keeping it accurate no matter how the render loop is actually scheduled.

Elapsed time derived from Date.now(), not accumulated per-tick

When the stopwatch starts, startTimestamp = Date.now() is captured once. currentElapsed() then always computes elapsed time as accumulatedMs + (Date.now() - startTimestamp) while running — the accumulated time from any previous run-then-stop segments, plus how long the current segment has been running, both measured against real timestamps rather than an incrementing counter.

requestAnimationFrame drives the display, not the timing

A requestAnimationFrame loop calls renderDisplay() on every frame while running, but the loop's only job is to repaint the display as often as the browser can manage — the actual elapsed-time value it renders always comes fresh from currentElapsed()'s timestamp math, so frame-rate variance never affects timing accuracy, only how smoothly the display updates.

Stop preserves exact accumulated time across sessions

Clicking Stop adds Date.now() - startTimestamp (the just-finished segment's real duration) into accumulatedMs and cancels the animation frame loop. Starting again later captures a new startTimestamp and resumes counting from the previously accumulated total — so multiple start/stop cycles never lose or double-count time.

Laps store total elapsed time; splits are derived

Clicking Lap pushes the current total elapsed time (not a duration) into the laps array. renderLaps() then computes each lap's split by subtracting the previous lap's total from the current one, displaying both the split and the running total for every lap, with the most recent lap listed first.

Step by step

How to Use

  1. 1
    Load the snippetClick "Lap Stopwatch with Splits" in the sidebar to load its HTML, CSS, and JS into the editor panels. The preview updates instantly.
  2. 2
    Edit the codeModify any panel — HTML, CSS, or JS. The preview refreshes as you type. Use Reset in each panel header to restore the original.
  3. 3
    Preview on devicesClick the Mobile (375px), Tablet (768px), or Desktop buttons in the preview header to check responsiveness.
  4. 4
    Export in your formatClick "HTML" to download a standalone file, "JSX" for a React component, "Tailwind" for a React + Tailwind CSS component, "Tailwind HTML" for a standalone HTML file with Tailwind CDN, "Vue" for a Vue 3 SFC with <template>/<script setup>/<style scoped>, or "Angular" for a standalone Angular .component.ts file. "Copy all" copies the full code to clipboard.
  5. 5
    Save your versionClick "Save as", type a name, and press Enter. Your snippet saves to IndexedDB and appears in the Saved tab.

Real-world uses

Common Use Cases

Fitness, running, and workout tracking apps
Track interval splits during a workout with an accurate, drift-free stopwatch.
Timed testing, cooking, or productivity tools
Any interface needing precise elapsed-time tracking with checkpoint recording.
Teaching timestamp-based timing over naive counters
A clear demonstration of why real timestamps beat incrementing a counter each tick for accuracy.
Dashboard widgets needing a precise running clock
A self-contained stopwatch component with lap history for any monitoring or session UI.

Got questions?

Frequently Asked Questions

setInterval and requestAnimationFrame callbacks don't fire at perfectly regular intervals — small delays accumulate over time. By deriving elapsed time as accumulatedMs + (Date.now() - startTimestamp), the displayed time is always mathematically correct regardless of any variance in how often the render loop actually runs.

It records the current total elapsed time (via currentElapsed()) into the laps array. The split time shown for each lap is then computed by subtracting the previous lap's total from the current one, not stored directly.

No — stopping adds the just-completed segment's duration into accumulatedMs, and restarting begins a new segment from a fresh startTimestamp, so total elapsed time across any number of stop/start cycles stays exactly accurate.

requestAnimationFrame syncs the display refresh to the browser's paint cycle, giving a smooth-looking update without wasting work when the tab isn't visible, while the actual timing math stays independent of the loop's exact frequency.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Hand this snippet's HTML, CSS, and JavaScript to an AI coding assistant like Claude and ask it to adapt "Lap Stopwatch with Splits" to your project — restyle it to match your design system, wire it up to real data instead of the static example, or port it to the framework you're building in.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a tools component called "Lap Stopwatch with Splits" using plain HTML, CSS, and vanilla JavaScript — no framework, no build step.

Requirements:
- Match the structure and behavior of the "Lap Stopwatch with Splits" snippet from the UI Snippets Library.
- Keep the markup semantic and the styling self-contained (no external dependencies beyond what the original snippet uses).
- Keep the JavaScript vanilla, with no framework runtime required.
- Make it easy to restyle via CSS custom properties or class overrides so it can be dropped into a real project.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="lsw-wrap">
  <div class="lsw-display" id="lswDisplay">00:00.00</div>

  <div class="lsw-controls">
    <button class="lsw-btn lsw-btn-primary" id="lswStartBtn">Start</button>
    <button class="lsw-btn" id="lswLapBtn" disabled>Lap</button>
    <button class="lsw-btn" id="lswResetBtn">Reset</button>
  </div>

  <div class="lsw-laps" id="lswLaps"></div>
</div>