react-custom-scrollbars-2
react-custom-scrollbars-2 copied to clipboard
[Enhancement] Pass some context to renderView
Problem context
When rendering my view, I had an issue with the space occupied by the scrollbar. I do not want the scrollbar to hover my content, but I don't want to leave a blank space when there is no scrollbar.
Suggested solution
The renderView property is a simple react component React.StatelessComponent<any>.
If you add a property for context it could open some rooms for several improvements :
interface ScrollbarsViewContext = { hasScrollbar: boolean; fullViewHeight: number; scrollbarWidth: number; scrollbarHeight: number; }
The first one clearly solves my problem, the others are just ideas from the top of my head.
Fair enough. I don't have a lot of time, but if you are happy to work up a PR for this I'll take a look.
Depending on your browser requirements though a slider that sits outside the container may be easier and v.possible with native browser css rules
I had the same issue, and I wish to share my solution.
I created a new wrapper component. Hopefully this will help others.
There is a bug with getValues() method, it will always return the same values for scrollHeight and clientHeight on the first render. So to fix this, I've added an init state value, which updates via the useEffect hook. This triggers the next useEffect hook which contains our value checking - if the scrollHeight is larger than the clientHeight then we set isScrollable to true.
Inside the renderView function, I'm adding the pr-4 class (this is a TailwindCSS class) to push the view away from the track.
This code contains customisation to the tracks. It also introduces 'pointer-events-none' (again, a TailwindCSS class) so that when the scrolling is active, the mouse pointer doesn't trigger any hover states on the content. Pretty nifty I think.
import React, {useState, useEffect, useRef} from 'react';
import {Scrollbars} from 'react-custom-scrollbars-2';
import classNames from 'classnames';
const Scroll = (props) => {
const vertTrackWidthChosen = '16px'; // Original is 6px
const horzTrackHeightChosen = '16px'; // Original is 6px
const [isSelectable, setIsSelectable] = useState(true);
const [isScrollable, setIsScrollable] = useState(false);
const scrollbars = useRef();
const [init, setInit] = useState(false);
useEffect(() => {
const values = scrollbars.current.getValues();
if (values?.scrollHeight > values?.clientHeight) setIsScrollable(true);
}, [init]);
useEffect(() => {
setInit(true);
}, []);
return (
<Scrollbars
ref={scrollbars}
hideTracksWhenNotNeeded
onScrollStart={() => setIsSelectable(false)}
onScrollStop={() => setIsSelectable(true)}
{...props}
renderThumbVertical={(props) => <div {...props} className="bg-green-300 rounded" />}
renderView={({style, ...props}) => {
return (
<div
className={classNames('', {
'pr-4': isScrollable,
})}
style={style}
{...props}
/>
);
}}
renderTrackHorizontal={({style, ...props}) => {
return <div {...props} className="" style={{...style, height: horzTrackHeightChosen}} />;
}}
renderTrackVertical={({style, ...props}) => {
return (
<div
{...props}
className="ml-16 top-0 bottom-0 right-0 p-0.5 bg-gray-900 bg-opacity-20"
style={{...style, width: vertTrackWidthChosen}}
/>
);
}}
>
<div
className={classNames('', {
'pointer-events-none': !isSelectable,
})}
>
{props.children}
</div>
</Scrollbars>
);
};
Use it like this
<Scroll thumbSize={30}>
_your content_
</Scroll>