Fixing horizontal scrolling in your DetailsList using ScrollablePane and Sticky

Posted Wednesday, October 3, 2018 1:44 PM by CoreyRoth

The  Fabric React DetailsList component is a great way to display your tabular data when building an SPFx web part.  It's nice, but if you have a lot of rows in your list, you might need a sticky header so that you can see which column you are looking at.  As a developer building out this scenario for the first time, you might run into guidance and a code sample from the ScrollablePane documentation.  I found this hard to find because I would expect this example to be linked to the DetailsList documentation.  This will get you up and going fairly quickly.  However, when you are implementing it using the code sample, you'll find that there isn't an event called onScroll on DetailsList when you are building an SPFx web part.  That's because that event doesn't exist in Fabric React 5.  Maybe you proceed anyways and notice that the sticky header is working just fine. At least you thogught it was working.

Here's where the problem starts.  if you have a lot of columns (or your users' screen resolution is very low), you may need to deal with horizontal scrolling.  Nothing good ever comes from horizontal scrolling.  When you need to horizontally scroll, a scrollbar appears in the sticky header.  Great.  That's exactly what you wanted.  The problem is the rows in the grid, don't scroll with it.  Now you have columns that don't line up to the data.  That's a problem. 

When trying to fix it, you might run into the following issue on GitHub.  This pointed me in the right direction.  The answer is to react to the scroll events and set the scrollLeft property to match.  You need to create a new function to listen to the scrolling of the div element.  This effectively responds to the scrolling of the div element where your content is and sets the scroll of the Sticky to match it.  It's pretty simple.

private handleScroll(event) {
let element = document.querySelector("[class*='stickyAbove-']");
if (element != null)
element.scrollLeft = event.target.scrollLeft;
}

Then all you need to do is add the event to your div element that contains the ScrollablePane.

<div
   style={{
     height: '1000px',
     position: 'relative',
     maxHeight: 'inherit'
     }}
    onScroll={this.handleScroll}
>

This helped me to part of the solution but not all of it.  This only handles when the user scrolls the data using the scrollbar at the bottom.  What we need to add to it is an event to respond to when the user scrolls the Sticky element.  I did this by registering an event handler in componentDidMount.  I used pure JavaScript in my example, but you could reference the Sticky component using componentRef if you wanted.

public componentDidMount(): void {
let stickyElemrent = document.querySelector("[class*='stickyAbove-']")
if (stickyElemrent != null) {
stickyElemrent.addEventListener('scroll', this.hnadleStickyScroll);
}
}

In my event handler, we have similar code except that we are getting a reference to the DetailsList element.

 private hnadleStickyScroll(event) {
let gridElement = document.querySelector("[class*='ms-DetailsList']");
if (gridElement)
gridElement.scrollLeft = event.target.scrollLeft;
}

Once you add this, you should be able to scroll your rows of content or the sticky header horizontally and they will stay in sync.  If you have run into this issue, give it a try.

Filed under: , ,

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)