Dynamic Display Dividers on Scrollable Dialog of Material UI
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.
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 Divider
s 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 oftarget
.
Credits & References
Check whether HTML element has scrollbars using JavaScript - GeeksforGeeks ↩︎
reactjs - How to describe type scroll events? - Stack Overflow ↩︎
reactjs - is this possible to get scroll position in material-ui select list on Scroll? - Stack Overflow ↩︎
browser - How to get scrollbar position with Javascript? - Stack Overflow ↩︎