React component for SimpleBar that provides custom scrollbars while maintaining native scroll performance
npx @tessl/cli install tessl/npm-simplebar-react@3.3.0SimpleBar React is a React component wrapper for SimpleBar, a custom scrollbar library that replaces browser default scrollbars with CSS-styled ones while maintaining native scroll performance. The component provides a declarative React interface for implementing custom scrollbars, supporting both regular JSX children and render prop patterns for advanced use cases.
npm install simplebar-reactimport SimpleBar from 'simplebar-react';
import 'simplebar-react/dist/simplebar.min.css';For CommonJS:
const SimpleBar = require('simplebar-react');
require('simplebar-react/dist/simplebar.min.css');import SimpleBar from 'simplebar-react';
import 'simplebar-react/dist/simplebar.min.css';
function App() {
return (
<SimpleBar style={{ maxHeight: 300 }}>
<div>
<p>Your scrollable content goes here...</p>
<p>Multiple lines of content...</p>
<p>That will show custom scrollbars when overflowing...</p>
</div>
</SimpleBar>
);
}The main React component that wraps content with custom scrollbars while maintaining native scroll behavior.
declare const SimpleBar: React.ForwardRefExoticComponent<
Props & React.RefAttributes<SimpleBarCore | null>
> & {
displayName: 'SimpleBar';
};
interface Props extends
Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>,
SimpleBarOptions {
children?: React.ReactNode | RenderFunc;
scrollableNodeProps?: {
ref?: any;
className?: string;
[key: string]: any;
};
}Usage Examples:
// Basic usage
<SimpleBar style={{ maxHeight: 400 }}>
<YourContent />
</SimpleBar>
// With options
<SimpleBar
forceVisible="y"
autoHide={false}
scrollbarMinSize={30}
>
<YourContent />
</SimpleBar>
// With scrollableNodeProps
<SimpleBar
scrollableNodeProps={{
ref: scrollableRef,
className: 'custom-scrollable',
'data-testid': 'scrollable-area'
}}
>
<YourContent />
</SimpleBar>Advanced usage pattern that provides access to internal DOM elements and their props.
type RenderFunc = (props: {
scrollableNodeRef: React.MutableRefObject<HTMLElement | undefined>;
scrollableNodeProps: {
className: string;
ref: React.MutableRefObject<HTMLElement | undefined>;
tabIndex: number;
role: string;
'aria-label': string;
};
contentNodeRef: React.MutableRefObject<HTMLElement | undefined>;
contentNodeProps: {
className: string;
ref: React.MutableRefObject<HTMLElement | undefined>;
};
}) => React.ReactNode;Usage Example:
<SimpleBar>
{({ scrollableNodeProps, contentNodeProps }) => (
<div {...scrollableNodeProps}>
<div {...contentNodeProps}>
<YourContent />
</div>
</div>
)}
</SimpleBar>Access to the underlying SimpleBar core instance for imperative operations.
// Ref type
type SimpleBarRef = SimpleBarCore | null;
// Core instance methods (from simplebar-core)
interface SimpleBarCore {
/** Recalculate scrollbar positions and visibility */
recalculate(): void;
/** Get the content element */
getContentElement(): HTMLElement | null;
/** Get the scrollable wrapper element */
getScrollElement(): HTMLElement | null;
/** Clean up and remove all event listeners */
unMount(): void;
/** Root element that SimpleBar was applied to */
el: HTMLElement;
}Usage Example:
import { useRef, useEffect } from 'react';
import SimpleBar from 'simplebar-react';
function MyComponent() {
const simpleBarRef = useRef<SimpleBarCore | null>(null);
useEffect(() => {
// Recalculate after content changes
simpleBarRef.current?.recalculate();
}, [someData]);
const scrollToBottom = () => {
const scrollElement = simpleBarRef.current?.getScrollElement();
if (scrollElement) {
scrollElement.scrollTop = scrollElement.scrollHeight;
}
};
return (
<SimpleBar ref={simpleBarRef}>
<YourContent />
</SimpleBar>
);
}Configuration options inherited from simplebar-core that control scrollbar behavior and appearance.
interface SimpleBarOptions {
/** Force scrollbar visibility: true (both), false (auto), 'x' (horizontal), 'y' (vertical) */
forceVisible?: boolean | 'x' | 'y';
/** Enable clicking on track to scroll (default: true) */
clickOnTrack?: boolean;
/** Minimum scrollbar size in pixels (default: 25) */
scrollbarMinSize?: number;
/** Maximum scrollbar size in pixels (default: 0 - no limit) */
scrollbarMaxSize?: number;
/** Custom CSS class names for scrollbar elements */
classNames?: Partial<ClassNames>;
/** ARIA label for accessibility (default: "scrollable content") */
ariaLabel?: string;
/** Tab index for keyboard navigation (default: 0) */
tabIndex?: number;
/** Custom scrollable element (overrides default) */
scrollableNode?: HTMLElement | null;
/** Custom content element (overrides default) */
contentNode?: HTMLElement | null;
/** Auto-hide scrollbars when not in use (default: true) */
autoHide?: boolean;
}Usage Examples:
// Force vertical scrollbar to always be visible
<SimpleBar forceVisible="y">
<YourContent />
</SimpleBar>
// Disable auto-hiding and set custom scrollbar size
<SimpleBar
autoHide={false}
scrollbarMinSize={30}
scrollbarMaxSize={100}
>
<YourContent />
</SimpleBar>
// Custom ARIA label and tab index for accessibility
<SimpleBar
ariaLabel="Chat messages"
tabIndex={-1}
>
<ChatMessages />
</SimpleBar>Customizable CSS class names for styling scrollbar elements.
interface ClassNames {
/** Content element class (default: 'simplebar-content') */
contentEl: string;
/** Content wrapper element class (default: 'simplebar-content-wrapper') */
contentWrapper: string;
/** Offset element class (default: 'simplebar-offset') */
offset: string;
/** Mask element class (default: 'simplebar-mask') */
mask: string;
/** Wrapper element class (default: 'simplebar-wrapper') */
wrapper: string;
/** Placeholder element class (default: 'simplebar-placeholder') */
placeholder: string;
/** Scrollbar handle class (default: 'simplebar-scrollbar') */
scrollbar: string;
/** Scrollbar track class (default: 'simplebar-track') */
track: string;
/** Height observer wrapper class (default: 'simplebar-height-auto-observer-wrapper') */
heightAutoObserverWrapperEl: string;
/** Height observer element class (default: 'simplebar-height-auto-observer') */
heightAutoObserverEl: string;
/** Visible state class (default: 'simplebar-visible') */
visible: string;
/** Horizontal orientation class (default: 'simplebar-horizontal') */
horizontal: string;
/** Vertical orientation class (default: 'simplebar-vertical') */
vertical: string;
/** Hover state class (default: 'simplebar-hover') */
hover: string;
/** Dragging state class (default: 'simplebar-dragging') */
dragging: string;
/** Scrolling state class (default: 'simplebar-scrolling') */
scrolling: string;
/** Scrollable state class (default: 'simplebar-scrollable') */
scrollable: string;
/** Mouse entered state class (default: 'simplebar-mouse-entered') */
mouseEntered: string;
}Usage Example:
<SimpleBar
classNames={{
wrapper: 'my-custom-wrapper',
track: 'my-custom-track',
scrollbar: 'my-custom-scrollbar'
}}
>
<YourContent />
</SimpleBar>import { useRef, useEffect } from 'react';
import SimpleBar from 'simplebar-react';
function ChatBox({ messages }) {
const scrollRef = useRef<SimpleBarCore | null>(null);
useEffect(() => {
// Auto-scroll to bottom when new messages arrive
const scrollElement = scrollRef.current?.getScrollElement();
if (scrollElement) {
scrollElement.scrollTop = scrollElement.scrollHeight;
}
}, [messages]);
return (
<SimpleBar
ref={scrollRef}
style={{ height: 400 }}
autoHide={false}
>
{messages.map(message => (
<div key={message.id}>{message.text}</div>
))}
</SimpleBar>
);
}<SimpleBar
style={{ maxHeight: 500 }}
classNames={{
track: 'data-table-scrollbar-track',
scrollbar: 'data-table-scrollbar-handle'
}}
scrollbarMinSize={40}
>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Role</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.role}</td>
</tr>
))}
</tbody>
</table>
</SimpleBar>For advanced use cases like react-window, you can use the render prop pattern to access internal elements:
import { FixedSizeList as List } from 'react-window';
<SimpleBar style={{ height: 400 }}>
{({ scrollableNodeProps, contentNodeProps }) => (
<div {...scrollableNodeProps}>
<List
height={400}
itemCount={1000}
itemSize={35}
>
{({ index, style }) => (
<div style={style}>
Item {index}
</div>
)}
</List>
</div>
)}
</SimpleBar>