React + TypeScript: Handling onScroll event

Updated: March 3, 2023 By: A Goodman 2 comments


The onScroll event occurs when an element’s scrollbar is being scrolled.

This article walks you through an end-to-end example of handling the onScroll event in a React application. We’ll use TypeScript and modern features of React including hooks and functional components. You won’t see old-fashioned stuff like class-based components or things relate to them.

The Complete Example

The simple app we are going to make contains an orange box, a list, and a progress bar. The box has a fixed height of 400px. The list resides inside the box and displays a large number of items. The progress bar indicates how many items were viewed (or more precisely, the percentage of items viewed) by the user when they scrolled down.


A demo is worth more than a thousand words. Here’s how our app works:

The Code

1. Create a new React project by executing the following command:

npx create-react-app kindacode_react_ts --template typescript

The project name is totally up to you.

2. The full source code in src/App.tsx with explanations:

// App.tsx
import React, { useState } from "react";

// Generate some dummy data
const DUMMY_DATA = Array.from({ length: 100 }, (x, i) => {
  return {
    id: i,
    title: `Item ${i}`,

const App = () => {
  const [progress, setProgress] = useState(0);

  // This function is triggered when the user scroll
  const scrollHandler = (event: React.UIEvent<HTMLDivElement>) => {
    const containerHeight = event.currentTarget.clientHeight;
    const scrollHeight = event.currentTarget.scrollHeight;

    const scrollTop = event.currentTarget.scrollTop;
    setProgress(((scrollTop + containerHeight) / scrollHeight) * 100);

  return (
      {/* The container */}
      <div style={styles.container} onScroll={scrollHandler}>
        {/* The list */}
        <div style={styles.list}>
          { => (
            // A single item
            <div style={styles.item} key={}>

      {/* The progress bar */}
      <div style={styles.progressBar}>
        <div style={{ ...styles.progressValue, width: `${progress}%` }}></div>
      <p style={styles.text}>{progress.toFixed(2)}%</p>

// Styling
const styles = {
  container: {
    width: 500,
    height: 400,
    margin: "30px auto",
    overflowY: "auto",
    overflowX: "hidden",
    background: "orange",
  list: {
    width: "100%",
  item: {
    margin: "20px 25px",
    padding: "30px 20px",
    boxShadow: "0 2px 4px #999",
    background: "purple",
    fontSize: "18px",
    textAlign: "center",
    color: "#fff",
  progressBar: {
    width: 600,
    height: 20,
    margin: "auto",
    backgroundColor: "#bbb",
  progressValue: {
    height: "100%",
    backgroundColor: "blue",
  text: {
    textAlign: 'center'
} as const;

export default App;

3. Run the project:

npm start

And go to http://localhost:3000 to check the result.


We’ve built a simple app to get a better understanding of the onScroll event in React and TypeScript. If you’d like to explore more new and interesting things in modern React and frontend development, take a look at the following articles:

You can also check our React category page and React Native category page for the latest tutorials and examples.

Notify of
Inline Feedbacks
View all comments
1 year ago

calculation formula is wrong
need to do so

setProgress((scrollTop / (scrollHeight - containerHeight)) * 100);

Related Articles