Detect when user has scrolled through a text to enable a button

Viewed 51

How to implement a "scroll detection" feature using React? I would like to present the user with a div with a given message, and enable a checkbox only once the user has scrolled through it. This is my current implementation, which is not working.

function Disclaimer({ text, checkboxText }) {
  const divRef = useRef();
  const [userHasReviewed, setUserHasReviewed] = useState(false);

  const scrollTracker = () => {
    if (divRef.current) {
      const { scrollTop, scrollHeight, clientHeight } =
        divRef.current;
      if (scrollTop + clientHeight === scrollHeight) {
        setUserHasReviewed(true);
      }
    }
  };

  return (
    <div>
      <div
        ref={divRef}
        onScroll={() => scrollTracker()}
      >
        {text}
      </div>
      <div>
        <Checkbox
          label={checkboxText}
          disabled={!userHasReviewed}
        />
      </div>
    </div>
  );
}

I've placed debug points inside of the scrollTracker function, but the debugger never enters the function. I think this is because the text is not large enough to actually overflow and require the scrolling space/action. In this case, how can I automatically detect this so that the userHasReviewed is set to true automatically?

2 Answers

The onScroll method will not fire if the element is not scrollable. Elements are not scrollable by default and you have to set the css property overflow:scroll for that div.

But perhaps if this is not what are looking for, what you need is the Intersection Observer API. Read the MDN doc here. It can observe the intersection between an element and the top-level document's viewport. You can tap in that information and display the checkbox.

For onScroll event to fire the user should be able to scroll. It's not the case for a normal div by default. To make it happen you need to set a height and overflow:auto or overflow:scroll for the div. As an example like so:

function App() {
  const divRef = React.useRef();
  const [userHasReviewed, setUserHasReviewed] = React.useState(false);

  const scrollTracker = () => {
    const { scrollTop, scrollHeight, clientHeight } = divRef.current;
    if (scrollTop + clientHeight === scrollHeight) {
      setUserHasReviewed(true);
    }
  };

  return (
    <div>
      <div className="text" ref={divRef} onScroll={() => scrollTracker()}>
        Le Lorem Ipsum est simplement du faux texte employé dans la composition
        et la mise en page avant impression. Le Lorem Ipsum est le faux texte
        standard de l'imprimerie depuis les années 1500, quand un imprimeur
        anonyme assembla ensemble des morceaux de texte pour réaliser un livre
        spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles,
        mais s'est aussi adapté à la bureautique informatique, sans que son
        contenu n'en soit modifié. Il a été popularisé dans les années 1960
        grâce à la vente de feuilles Letraset contenant des passages du Lorem
        Ipsum, et, plus récemment, par son inclusion dans des applications de
        mise en page de texte, comme Aldus PageMaker.
      </div>
      <input type="checkbox" disabled={!userHasReviewed} />{" "}
      {!userHasReviewed ? "Disabled" : "Non disabled"}
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById("root")
);
.text {
  height: 50px;
  overflow: auto;
  background: lightgray;
  padding: 1rem;
  border-radius: 1rem;
  margin-bottom: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related