Hi,
I opened an issue at https://github.com/malte-wessel/react-custom-scrollbars/issues/30, looking for a way to leverage react-virtualized with react-custom-scrollbars.
As the author @malte-wessel mentioned, this'll require changes in both libraries. He seems keen on making the changes on his end, so I'm hopeful that I can interest you in doing the same? :)
Interesting suggestion @t1mmen. I've commented on the issue you linked, although unless I'm missing something... I don't initially see any changes that react-custom-scrollbars would need to make.
I have a proof-of-concept working in a branch (issues/143).
Started to integrate with react-custom-scrollbars but then realized that Grid already had all of the properties it needed (scroll top/left, client width/height, etc.). These properties are already being passed to the onScroll callback or, better yet, could be accessed via the ScrollSync component. So I put together the following demo:

The code in question is:
<ScrollSync>
{({ clientHeight, clientWidth, onScroll, scrollHeight, scrollLeft, scrollTop, scrollWidth }) => {
const x = scrollLeft / (scrollWidth - clientWidth)
const y = scrollTop / (scrollHeight - clientHeight)
return (
<AutoSizer disableHeight>
{({ width }) => (
<div style={{
backgroundColor: `rgb(${Math.round(y * 255)}, ${Math.round(x * 255)}, 255)`,
color: `rgb(${Math.round(255 * y)}, ${Math.round(255 * y)}, ${Math.round(255 * y)})`,
height,
width
}}>
<Grid
className={styles.BodyGrid}
columnWidth={columnWidth}
columnsCount={columnsCount}
height={height}
onScroll={onScroll}
overscanColumnsCount={overscanColumnsCount}
overscanRowsCount={overscanRowsCount}
renderCell={this._renderBodyCell}
rowHeight={rowHeight}
rowsCount={rowsCount}
width={width}
/>
</div>
)}
</AutoSizer>
)
}}
</ScrollSync>
Note that this requires 2 small changes to ScrollSync:
AutoSizer nested inside of a ScrollSync and the first time the ScrollSync child is rendered, the width/height are 0.) This probably has a simple fix but it's midnight here now and I'm sleepy. :)That's looking pretty slick, good work! I'm excited to give it a try in my project!
Great! :)
I'll try to get it finished up this evening after work. (This is a side project for me so I can't do much with it during the day.)
I completely understand @bvaughn – no rush, just thankful you've decided to take this issue on! Appreciate your hard work :+1:
Just released version 5.5.0 with this feature. Enjoy~
Updated demo: https://bvaughn.github.io/react-virtualized/?component=ScrollSync
Source code: https://github.com/bvaughn/react-virtualized/blob/master/source/ScrollSync/ScrollSync.example.js
Wow, that was quick :) I'll have a look at it!
Sadly, it looks like both libraries do not work well together :( I tried two approaches:
Scrollbars component directly into the Grid component hereScrollbars component. This could be due to the fact that the Scrollbars component wraps the scrollable element and passes the events from there. This approach would also assume that components like Grid would implement the Scrollbars component, which is not desired. It also introduces a new layer between Grid and the higher order componentsGrid component with ScrollbarsScrollbars renders the scrollable element itself and there is currently no way to replace this behaviour.@t1mmen Nevertheless it should be easy to implement you own scrollbars with the changes in v5.5.0. You only need to render the tracks and thumbs and update their styles like I did here
Quick update to this issue in case anyone else sees it and is curious. react-virtualized now supports a custom renderer prop- renderCellRanges. This function is responsible for rendering (and positioning) the visible range of cells. Its signature is:
function ({
columnMetadata:Array<Object>,
columnStartIndex: number,
columnStopIndex: number,
renderCell: Function,
rowMetadata:Array<Object>,
rowStartIndex: number,
rowStopIndex: number
}): Array<PropTypes.node>
Grid provides a default implementation of this (obviously) but you can override it if you want to render customized UI along with your cells (eg. gantt chart style overlays, custom scrollbars, etc). Doing it this way is a little more work but it gives you much greater flexibility in what your grid looks like _and_ react-virtualized still manages all of the data windowing for you.
If you're curious, you can see the default implementation here: https://github.com/bvaughn/react-virtualized/blob/master/source/Grid/Grid.js#L729
Hey, thank you for your help guys,
Im having hard times making these 2 packages work together, Im using react-visualized Table component and I don't have renderCellRanges to use and I`m kinda lost.
I would love for some help and love, thank you guys ! :)
Great product by the way!
Hi @amitripshtos,
RV Table uses a Grid inside of itself and passes props down to it. It renders headers above the Grid, but those aren't scrollable anyway. So if you want custom scrollbars on the Grid- you should still be able to use the renderCellRanges approach mentioned above.
Maybe something more or less like this?
import { defaultCellRangeRenderer, Table } from 'react-virtualized'
function cellRangeRenderer (props) {
const children = defaultCellRangeRenderer(props) // Render Table rows
children.push(
// Push custom scrollbar container
)
return children
}
function renderTableWithCustomScrollbars (tableProps) {
return (
<Table
{...tableProps}
cellRangeRenderer={cellRangeRenderer}
gridStyle={{
// I'm unsure about this part because
// I'm unfamiliar with react-custom-scrollbars
overflowY: 'hidden'
}}
/>
)
}
@amitripshtos Were you able to get these two packages to work together? Also having troubles trying to get these to work and can't quite figure it out.
Actually I did not, just gave up and used normal scrollbar :)
Hello to all, and sorry for my english
I tried to integrate the list of react-virtualized with react-custom scrollbars.
I solved this way, maybe just a little bit tricky :D
There are two div. One with the list and one with the scrollbar.
Scrollbar's div have height = itemsCount * itemHeight in order to have the same content as List.
So, i connected the two components' scroll action. When you scroll from List, also scrollbar's div scrolls. When you scroll from scrollbar, also the List scroll.
import React from 'react';
import { Scrollbars } from 'react-custom-scrollbars';
import {
AutoSizer,
List,
} from 'react-virtualized';
import scrollbarSize from 'dom-helpers/util/scrollbarSize';
type Props = {
items: Array<*>,
height: number,
rowRender: Function,
rowHeight: number,
lightScrollbar?: boolean,
}
type State = {
scrollTop: number,
}
export default class VirtualizedListScroll extends React.Component {
props: Props;
state: State;
constructor(props: Props) {
super(props);
this.state = {
scrollTop: 0,
};
}
customScrollBar = null;
handleCustomScroll = (event: Object) => {
if (event) {
const { target } = event;
if (!(target instanceof HTMLDivElement)) {
return;
}
this.setState({ scrollTop: target.scrollTop });
}
}
handleVirtualizedScroll = (event: Object) => {
if (event && event.scrollTop) {
this.setState({ scrollTop: event.scrollTop });
if (this.customScrollBar) {
this.customScrollBar.scrollTop(event.scrollTop);
}
}
}
render() {
const propsHeight = this.props.height;
const itemsCount = this.props.items.length || 0;
const rowRender = this.props.rowRender;
const rowHeight = this.props.rowHeight;
const scrollbarColor = this.props.lightScrollbar ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.2)';
const scrollBarWidth = ((itemsCount * rowHeight) > propsHeight) ? scrollbarSize() : 0;
return (
<AutoSizer disableHeight>
{({ width }) => (
<div className="VirtualizedScroll" style={{ heigth: `${propsHeight}px`, width }}>
<List
style={{ zIndex: '1', position: 'absolute' }}
{...this.props}
width={width + scrollBarWidth}
height={propsHeight}
scrollTop={this.state.scrollTop}
rowCount={itemsCount}
rowHeight={rowHeight}
onScroll={this.handleVirtualizedScroll}
rowRenderer={rowRender}
/>
<Scrollbars
className="ScrollContent"
style={{ height: `${propsHeight}px`, width: scrollbarSize() }}
onScroll={this.handleCustomScroll}
ref={scrollbars => { this.customScrollBar = scrollbars; }}
renderThumbVertical={({ style }) => <div style={{ ...style, backgroundColor: scrollbarColor, borderRadius: '3px' }} />}
>
<div className="ScrollBarContainer" style={{ height: (itemsCount * rowHeight) }} />
</Scrollbars>
</div>
)}
</AutoSizer>
);
}
}
And this is the CSS
.VirtualizedScroll {
position: relative;
overflow-x: hidden;
}
.ScrollContent {
background: transparent;
z-index: 2;
float: right;
}
.ScrollBarContainer {
width: auto;
}
@enjoyyournoise yeah, yours is too complicated and not that efficient.
I've found that you can just rewrite the Grid's _onScroll method and it will work like a charm. Actually, the only thing preventing on using inner _onScroll in the first place is container node check.
@bvaughn can you maybe add a second parameter to _onScroll that let you pass event from another container?
@bvaughn Hey! I'm back at it again.
Seems like integrating react-custom-scrollbars with Table is a bit tricky, since the Grid component, to which this package should be applied, is obscured inside. Might you suggest way to do it properly?
Was hoping to be able to get custom scrollbars into the table as well. @5angel did you come up with/get any suggestions for solutions around how to do this cleanly? I took a quick peek at the source and it didn't look like there was any easy way to get at wrapping the grid component in the table.
@MrMint yeah, that was my first thought too. Well, there is a way—you might want to add gridrenderer prop, which will pass through the Grid element, allowing you to wrap it in custom scrollbars. That's still a bit hacky and not really useful outside that particular use case, but seems feasible at least.
That's why I asked @bvaughn if he has some thoughts already.
Got react-custom-scrollbars working with react-virtualized.Table using windowScroller. Had to make headerRow fixed to have it always on top, also it should always have background.
Here is the demo: https://codesandbox.io/s/32m23wyo9m
UPD: realized that windowScroller is not needed, only autoHeight prop is enough, so removed it. https://codesandbox.io/s/5vvq2wpln4
Most helpful comment
Got
react-custom-scrollbarsworking withreact-virtualized.TableusingwindowScroller. Had to makeheaderRowfixed to have it always on top, also it should always have background.Here is the demo: https://codesandbox.io/s/32m23wyo9m
UPD: realized that
windowScrolleris not needed, onlyautoHeightprop is enough, so removed it. https://codesandbox.io/s/5vvq2wpln4