Vali Talpas
Vali Talpas

Reputation: 35

Material-UI: Trigger transition when scroll to element

I use react with Material-UI for my website and I would like to add some transitions. I've used a button so far to make a component appear, but I want it to appear when I scroll to the component then the transition trigger. I am using <Grow/> component from Material-UI, can you help me with that?

Upvotes: 2

Views: 4323

Answers (1)

NearHuscarl
NearHuscarl

Reputation: 81390

You can listen to the scroll event in the container element and detect whether the elements inside it is in the viewport like below:

function Scroller({ className, children, trackIds, onScrollToElement }) {
  return (
    <div
      className={className}
      onScroll={(e) => {
        for (let i = 0; i <= trackIds.length - 1; i++) {
          const id = trackIds[i];
          const trackedEl = document.getElementById(id);
          const scrollerEl = e.currentTarget;

          if (
            scrollerEl.scrollTop >
            trackedEl.offsetTop + trackedEl.offsetHeight - scrollerEl.offsetHeight
          ) {
            onScrollToElement(trackedEl);
          }
        }
      }}
    >
      {children}
    </div>
  );
}

Explanation

  • scrollerEl is the scrollable container element. Make sure to set the overflow CSS property of this element to auto to show the scrollbar when there is not enough space.
  • trackedEl is the child element inside the scrollable container to keep track of, when the user scrolls to the trackedEl, the callback onScrollToElement is invoked.
  • scrollerEl.scrollTop: number of pixels scrolled vertically. This is the scroll 'progress'. Before you scroll, the value is 0, as you are scrolling down the value is increase by the pixels you've scrolled.
  • trackedEl.offsetTop + trackedEl.offsetHeight - scrollerEl.offsetHeight: The number of pixels you have to scroll down to see the trackedEl
    • trackedEl.offsetTop: The distance in pixel of the scrollerEl top position to the trackedEl top position.
    • trackedEl.offsetHeight: The height of trackedEl including padding and border. This means you have to fully see the trackedEl before onScrollToElement fires
    • scrollerEl.offsetHeight: The height of scrollerEl. Subtracting this because before you start scrolling, you've already seen the top part of the container.

Usage

const classes = useStyles();
const [showButton, setShowButton] = useState(false);

return (
  <Scroller
    className={classes.container}
    trackIds={["myButton"]}
    onScrollToElement={(el) => {
      if (el.id === "myButton" && !showButton) {
        setShowButton(true);
      }
    }}
  >
    <div className={classes.topContent}>
      <Typography variant="h4">Top content</Typography>
    </div>
    <div className={classes.buttonContent}>
      <Grow in={showButton}>
        <Button id="myButton" variant="contained" color="primary">
          Primary
        </Button>
      </Grow>
    </div>
  </Scroller>
);

Props:

  • trackIds: List of ids of the elements to keep track of in the Scroller. If we track every elements inside Scroller, it will affect the performance in complex UI.

  • onScrollToElement: A callback that is executed when a tracked element is scrolled into view.

Live Demo

Edit 67105187/material-ui-transition-when-scroll

Upvotes: 1

Related Questions