How to Create a Custom Scrollbar in React

4 min read

Scrollbars are one of the most overlooked UI elements in web applications. The default browser scrollbar often doesn’t match the design language of modern apps.

In this guide, you’ll learn how to create a custom scrollbar in React, ranging from simple CSS styling to a fully custom React-powered scrollbar component.

We’ll cover:

Styling the native scrollbar with CSS

Creating a reusable custom scrollbar component in React

Handling scroll synchronization and thumb dragging

  1. Styling the Native Scrollbar (Quick Method)

The easiest way to customize scrollbars in React is with CSS pseudo-elements.

This works in Chrome, Edge, and Safari using ::-webkit-scrollbar.

Example /* scrollbar width */ ::-webkit-scrollbar { width: 10px; }

/* scrollbar track */ ::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; }

/* scrollbar thumb */ ::-webkit-scrollbar-thumb { background: #888; border-radius: 10px; }

/* hover effect */ ::-webkit-scrollbar-thumb:hover { background: #555; }

Then apply it to your scroll container.

function ScrollContainer() { return (

{Array.from({ length: 50 }).map((_, i) => (

Item {i}

))} ); } Pros

Very simple

No JavaScript needed

Good for quick styling

Cons

Limited control

Not fully cross-browser

Cannot fully customize behavior

For full control, we need to build a custom scrollbar component.

  1. Building a Custom Scrollbar Component in React

Instead of styling the browser scrollbar, we hide it and build our own scrollbar UI.

Concept

The custom scrollbar consists of three parts:

Container — wrapper component

Scrollable Content

Scrollbar Track + Thumb

Project Structure components/ CustomScrollbar.jsx CustomScrollbar.css 3. Creating the Custom Scrollbar Component CustomScrollbar.jsx import { useRef, useState, useEffect } from "react"; import "./CustomScrollbar.css";

export default function CustomScrollbar({ children }) { const contentRef = useRef(null); const [thumbHeight, setThumbHeight] = useState(20); const [thumbTop, setThumbTop] = useState(0);

useEffect(() => { const el = contentRef.current;

const updateThumb = () => {
  const { scrollHeight, clientHeight, scrollTop } = el;

  const height = Math.max(
    (clientHeight / scrollHeight) * clientHeight,
    20
  );

  const top = (scrollTop / scrollHeight) * clientHeight;

  setThumbHeight(height);
  setThumbTop(top);
};

updateThumb();
el.addEventListener("scroll", updateThumb);

return () => el.removeEventListener("scroll", updateThumb);

}, []);

return (

{children}

  <div className="scrollbar">
    <div
      className="scroll-thumb"
      style={{
        height: thumbHeight,
        transform: `translateY(${thumbTop}px)`
      }}
    />
  </div>
</div>

); } 4. Styling the Scrollbar CustomScrollbar.css .scroll-container { position: relative; height: 300px; }

.scroll-content { height: 100%; overflow-y: scroll; padding-right: 10px; }

/* hide native scrollbar */ .scroll-content::-webkit-scrollbar { display: none; }

.scrollbar { position: absolute; right: 2px; top: 0; width: 8px; height: 100%; background: transparent; }

.scroll-thumb { width: 100%; background: #888; border-radius: 4px; position: absolute; cursor: pointer; } 5. Using the Custom Scrollbar import CustomScrollbar from "./CustomScrollbar";

function App() { return ( {Array.from({ length: 50 }).map((_, i) => (

Item {i}

))} ); }

export default App;

Now your React app uses a custom scrollbar instead of the native one.

  1. Adding Drag Support (Advanced)

To make the scrollbar thumb draggable, we handle mouse events.

Example logic:

const handleMouseDown = (e) => { const startY = e.clientY;

const onMouseMove = (moveEvent) => { const delta = moveEvent.clientY - startY; contentRef.current.scrollTop += delta * 2; };

const onMouseUp = () => { document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mouseup", onMouseUp); };

document.addEventListener("mousemove", onMouseMove); document.addEventListener("mouseup", onMouseUp); };

Attach it to the thumb:

7. Libraries That Provide Custom Scrollbars

If you prefer a production-ready solution, consider these libraries:

react-custom-scrollbars

simplebar-react

react-scrollbars-custom

These libraries handle:

touch support

accessibility

performance optimization

cross-browser compatibility

Conclusion

Custom scrollbars can significantly improve the visual polish and user experience of your React applications.

You have three main options:

Method Difficulty Flexibility CSS Scrollbar Styling Easy Low Custom React Component Medium High Library Solution Easy Very High

For small projects, CSS styling is enough. For design-heavy applications like dashboards or design systems, building a custom React scrollbar provides much greater control.