react-custom-scrollbars and react-scrollbars-custom are both React components designed to replace native browser scrollbars with customizable, cross-browser consistent alternatives. react-custom-scrollbars was one of the earliest and most popular solutions, offering a simple API to style scrollbars across different operating systems. react-scrollbars-custom emerged later as a modern alternative, focusing on better TypeScript support, more flexible styling options, and improved handling of native scrollbar behavior without hiding it completely. Both aim to solve the inconsistency of native scrollbars across Windows, macOS, and Linux, but they differ in their approach to DOM structure, performance, and long-term maintenance.
Consistent scrollbar styling across browsers is a common design requirement, but native scrollbars vary wildly between Windows, macOS, and Linux. react-custom-scrollbars and react-scrollbars-custom both address this by wrapping content in custom DOM structures that mimic scrolling behavior. However, their age, maintenance status, and technical implementation differ significantly. Let's look at how they handle rendering, styling, and React integration.
react-custom-scrollbars is effectively deprecated.
findDOMNode) that trigger warnings in Strict Mode.// react-custom-scrollbars: Legacy patterns
import { Scrollbars } from 'react-custom-scrollbars';
// May trigger warnings in React 18+ Strict Mode
<Scrollbars style={{ width: 500, height: 300 }}>
<div>Content</div>
</Scrollbars>
react-scrollbars-custom is actively maintained (relative to the alternative).
// react-scrollbars-custom: Modern patterns
import { Scrollbars } from 'react-scrollbars-custom';
// Compatible with React 18+ Strict Mode
<Scrollbars style={{ width: 500, height: 300 }}>
<div>Content</div>
</Scrollbars>
react-custom-scrollbars uses inline styles and specific class names.
// react-custom-scrollbars: Inline styles
<Scrollbars
style={{ width: 500, height: 300 }}
thumbSize={{ width: 8, height: 8 }}
renderThumb={(props) => <div {...props} style={{ ...props.style, backgroundColor: '#333' }} />}
>
<div>Content</div>
</Scrollbars>
react-scrollbars-custom uses a CSS-class-based system with a wrapper.
// react-scrollbars-custom: CSS class targeting
<Scrollbars
style={{ width: 500, height: 300 }}
renderer={({ elementRef, ...restProps }) => (
<div ref={elementRef} {...restProps} className="my-custom-scroll" />
)}
>
<div>Content</div>
</Scrollbars>
/* Targeting internal elements via CSS */
.my-custom-scroll .rsb__thumb {
background-color: #333;
border-radius: 4px;
}
react-custom-scrollbars creates a fixed nested structure.
// react-custom-scrollbars: Fixed structure
// Internally renders:
// <div> (wrapper)
// <div> (content container - absolute)
// {children}
// </div>
// <div> (scrollbar elements)
// </div>
react-scrollbars-custom allows more control over the element refs.
// react-scrollbars-custom: Ref forwarding
const scrollRef = useRef(null);
<Scrollbars
ref={scrollRef}
style={{ width: 500, height: 300 }}
>
<div>Content</div>
</Scrollbars>
// Access underlying methods
scrollRef.current.scrollTop(100);
react-custom-scrollbars hides native scrollbars completely.
// react-custom-scrollbars: JS-driven scroll
// Relies on listening to wheel/touch events and updating state
// Can feel less smooth on touch devices
<Scrollbars onScroll={(e) => console.log(e)}>
<div>Content</div>
</Scrollbars>
react-scrollbars-custom attempts to preserve native behavior where possible.
// react-scrollbars-custom: Native styling option
// Can use CSS to style native scrollbars instead of JS replacement
<Scrollbars
style={{ width: 500, height: 300 }}
disableNativeScrollbar={false} // Keeps native, styles it
>
<div>Content</div>
</Scrollbars>
react-custom-scrollbars relies heavily on JS for cross-browser consistency.
/* react-custom-scrollbars: Limited CSS hook usage */
.scrollbar-track {
/* Must be applied via props or global CSS overrides */
}
react-scrollbars-custom leverages modern CSS where possible.
/* react-scrollbars-custom: Can combine with native CSS */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-thumb {
background: #333;
}
Despite their differences, both packages solve the same core problem with similar high-level APIs.
<Scrollbars> component.style, className, and children props.// Both packages share this basic usage pattern
<Scrollbars style={{ height: 400 }}>
<div>Long content...</div>
</Scrollbars>
onScroll callbacks.// Both support programmatic control
const ref = useRef();
ref.current.scrollTop(100); // Works in both (with slight API diffs)
// Both support auto-sizing
<Scrollbars autoHeight autoHeightMax={300}>
<div>Content</div>
</Scrollbars>
// Both allow custom thumb rendering
<Scrollbars renderThumb={(props) => <div {...props} className="custom-thumb" />}>
<div>Content</div>
</Scrollbars>
react-scrollbars-custom handles hydration mismatches better in practice.// Both can be rendered on server
// But react-scrollbars-custom reduces hydration warnings
| Feature | Shared by Both |
|---|---|
| Core Component | <Scrollbars> wrapper |
| Props | style, className, onScroll |
| Sizing | autoHeight, autoWidth |
| Customization | renderThumb, renderTrack |
| Scroll Control | Ref-based methods (scrollTop) |
| SSR | Supported (with caveats) |
| Feature | react-custom-scrollbars | react-scrollbars-custom |
|---|---|---|
| Maintenance | β Deprecated / Unmaintained | β Actively Maintained |
| React Version | β οΈ Legacy (Strict Mode warnings) | β Modern (React 18+ ready) |
| TypeScript | β Community types only | β Built-in TS support |
| Scroll Engine | JS Simulation | Hybrid (Native + JS) |
| Touch Support | β οΈ Poor momentum scrolling | β Better touch handling |
| Styling | Inline styles | CSS Classes + Inline |
react-custom-scrollbars is a legacy solution π°οΈ. It served the community well for many years but has fallen behind modern React standards. Using it today introduces technical debt, potential bugs in Strict Mode, and lack of future support. Only use it if you are stuck maintaining an old app.
react-scrollbars-custom is the modern successor π οΈ. It offers better TypeScript integration, respects native browser behaviors more, and is safer for new projects. However, before adding any dependency, consider if modern CSS (::-webkit-scrollbar or scrollbar-width) can solve your design needs without JS overhead.
Final Thought: For new projects, prefer react-scrollbars-custom if JS control is strictly required. Otherwise, lean on native CSS scrollbar styling for better performance and less bundle weight. Avoid react-custom-scrollbars entirely in greenfield development.
Choose react-custom-scrollbars only if you are maintaining a legacy codebase that already depends on it and migration is too costly. It is widely considered deprecated and unmaintained, with known issues regarding modern React versions (like Strict Mode) and server-side rendering. Do not start new projects with this package as it lacks active support and may break with future React updates.
Choose react-scrollbars-custom if you need a actively maintained solution with better TypeScript definitions and more control over the scrollbar appearance without completely replacing the native engine. It is suitable for projects that require consistent styling across browsers but still want to leverage native scrolling performance where possible. However, evaluate if you actually need a custom scrollbar, as modern CSS solutions might suffice for simpler use cases.
requestAnimationFrame for 60fpsnpm install react-custom-scrollbars --save
This assumes that youβre using npm package manager with a module bundler like Webpack or Browserify to consume CommonJS modules.
If you donβt yet use npm or a modern module bundler, and would rather prefer a single-file UMD build that makes ReactCustomScrollbars available as a global object, you can grab a pre-built version from unpkg. We donβt recommend this approach for any serious application, as most of the libraries complementary to react-custom-scrollbars are only available on npm.
This is the minimal configuration. Check out the Documentation for advanced usage.
import { Scrollbars } from 'react-custom-scrollbars';
class App extends Component {
render() {
return (
<Scrollbars style={{ width: 500, height: 300 }}>
<p>Some great content...</p>
</Scrollbars>
);
}
}
The <Scrollbars> component is completely customizable. Check out the following code:
import { Scrollbars } from 'react-custom-scrollbars';
class CustomScrollbars extends Component {
render() {
return (
<Scrollbars
onScroll={this.handleScroll}
onScrollFrame={this.handleScrollFrame}
onScrollStart={this.handleScrollStart}
onScrollStop={this.handleScrollStop}
onUpdate={this.handleUpdate}
renderView={this.renderView}
renderTrackHorizontal={this.renderTrackHorizontal}
renderTrackVertical={this.renderTrackVertical}
renderThumbHorizontal={this.renderThumbHorizontal}
renderThumbVertical={this.renderThumbVertical}
autoHide
autoHideTimeout={1000}
autoHideDuration={200}
autoHeight
autoHeightMin={0}
autoHeightMax={200}
thumbMinSize={30}
universal={true}
{...this.props}>
);
}
}
All properties are documented in the API docs
Run the simple example:
# Make sure that you've installed the dependencies
npm install
# Move to example directory
cd react-custom-scrollbars/examples/simple
npm install
npm start
# Make sure that you've installed the dependencies
npm install
# Run tests
npm test
# Run code coverage. Results can be found in `./coverage`
npm run test:cov
MIT