Hide top divider while scrolling to the top, hide bottom divider while scrolling to the end.

首发于[Dialog] Add Divider to Dialog · Issue #3155 · mui-org/material-ui · GitHub,故用英文行文。

Example

Here is an example on CodeSandbox.

dialog-example

Details

Create two variables to control dividers.

const [topDivider, setTopDivider] = useState(false);
const [bottomDivider, setBottomDivider] = useState(false);

Create a function to initilize status of dividers. Because Dialog have its own “lifecycle”. (You will see the explanation below)

const initializeDividers = () => {
  setTopDivider(false);
  setBottomDivider(false);

  /* ... */
};

Detect if scrollbar exist by comparing scrollHeight with clientHeight.[1]

The id in getElementById is for DialogContent.

const initializeDividers = () => {
  /* ... */

  const dialogContent = document.getElementById('dialog-content');

  if (dialogContent !== null) {
    if (dialogContent.scrollHeight > dialogContent.clientHeight) {
      setBottomDivider(true);
    }
  }
};

Adding initializeDividers to Dialog in onEnter of TransitionProps. Because display of Dialog is control by open. (Now you know why we don’t use Effect Hook) You will get null if you are using React Effect Hook to get element.

<Dialog
  open={/* variable from caller */}
  TransitionProps={{
    onEnter: initializeDividers,
  }}
  scroll="paper"
>

{/* ... */}

Add Dividers before & after DialogContent with its variable from State Hook. And don’t forget to set a id for DialogContent.

{topDivider ? <Divider /> : null}
<DialogContent id="dialog-content">
  {/* ... */}
</DialogContent>
{bottomDivider ? <Divider /> : null}

Now let’s handle the scrolling.

You need to listen the onScroll event in DialogContent.

const handleScrolling = (e: React.UIEvent<HTMLDivElement>) => {
  /* ... */
};

/* ... */

<DialogContent id="dialog-content" onScroll={handleScrolling}>
  {/* ... */}
</DialogContent>

Assert the type of event.target to HTMLDivElement.[2]

const handleScrolling = (e: React.UIEvent<HTMLDivElement>) => {
  if (e === undefined) {
    return;
  }

  const { scrollTop, scrollHeight, offsetHeight } = e.currentTarget;

  /* ... */
};

Compare the scrollTop with the difference between scrollHeight and scrollHeight.[3] [4]

const handleScrolling = (e: React.UIEvent<HTMLDivElement>) => {
  /* ... */

  setTopDivider(scrollTop !== 0);
  setBottomDivider(
    scrollTop !== scrollHeight - offsetHeight
  );
};

Updates

  • 4/6/2022: Use currentTarget instead of target.

Credits & References


  1. Check whether HTML element has scrollbars using JavaScript - GeeksforGeeks ↩︎

  2. reactjs - How to describe type scroll events? - Stack Overflow ↩︎

  3. reactjs - is this possible to get scroll position in material-ui select list on Scroll? - Stack Overflow ↩︎

  4. browser - How to get scrollbar position with Javascript? - Stack Overflow ↩︎