I'm building a custom video player in React and I'm having trouble aligning the time displayed on hover over the progress bar with the actual seek time used when clicking.
Problem I use an as the progress bar.
On onMouseMove, I calculate the percentage based on event.clientX and show a tooltip (indicadorRef) displaying the estimated time for that position.
The time displayed on hover looks visually correct.
However, when the user clicks (using onChange), the actual seek time does not exactly match the hovered time — usually off by a small fraction of a second.
I've tried rounding values and aligning steps, but small mismatches remain.
Example:
const handleHoverProgress = (event) => {
if (!isPlayerReady) return;
const rect = inputProgressRef.current.getBoundingClientRect();
const x = event.clientX - rect.left;
const percentage = Math.max(0, Math.min(1, x / rect.width));
const min = parseFloat(inputProgressRef.current.min);
const max = parseFloat(inputProgressRef.current.max);
const step = parseFloat(inputProgressRef.current.step) || 0.001;
let value = min + percentage * (max - min);
value = Math.round(value / step) * step;
value = parseFloat(value);
indicadorRef.current.textContent = formatTime(value * duration);
indicadorRef.current.style.visibility = "visible";
let indicatorX = x - indicadorRef.current.offsetWidth / 2;
indicatorX = Math.max(0, Math.min(rect.width - indicadorRef.current.offsetWidth, indicatorX));
indicadorRef.current.style.left = `${indicatorX}px`;
};
ReactPlayer setup:
<ReactPlayer
ref={playerRef}
url={currentVideoUrl}
playing={playing}
volume={volume}
onProgress={({ played }) => setPlayed(played)}
onDuration={setDuration}
onReady={() => setIsPlayerReady(true)}
controls={false}
width="100%"
height="100%"
progressInterval={100}
/>
Range input:
<input
ref={inputProgressRef}
onMouseMove={handleHoverProgress}
type="range"
min={0}
max={1}
step={0.001}
value={played}
onChange={(e) => handleSeek(parseFloat(e.target.value))}
className="progress-bar"
/>
What I’ve tried Matching the tooltip value with the seek value by using the same percentage calculation.
Rounding to the nearest step to avoid floating-point issues (e.g., 0.73899999).
Using progressInterval={100} on ReactPlayer for more frequent updates.
The issue Despite all this, the hovered time and the actual seek time don’t perfectly match after clicking. Sometimes it’s off by a small fraction of a second or by one second depending on rounding behavior.
What I’m looking for How can I ensure that the time shown on hover exactly matches the time that the video seeks to when the user clicks?
Technologies React
ReactPlayer
Any help or suggestions are appreciated. Thank you!
