2

I want to create a div, which shows blurr on the bottom of the div (when overflow exists). The issue is that the div contains props.children, which also consist of other components / html tags inside.

I tried using ref (React.useRef), but the ref is set even before the children are renderen. I tried using useEffect with the ref, but still when I use for example element.current.scrollbarHeight I get 0.

How can I check if the rendered div (with children) has overflow? (I am using a functional component)

<div> {props.children} </div> 

For generating the blurr I am using styled-components.

11
  • Can you please share the all the code to be able to help? Commented Jan 25, 2021 at 11:22
  • Dear @KhaledAhmed, actually that <div>... is the only thing I need help with. The only thing there I added with styled-components is the height of the div, to 280px. I just want to find out if the props.children will cause an overflow. I do not know what will the props.children contain, it almost always has a different length and content. Commented Jan 25, 2021 at 11:28
  • 1
    I'm not sure it will ever be possible to know if arbitrary children are fully rendered without each one offering specialized callbacks. As such, it might be better to watch the element for size changes, by setting up something along the lines of the ResizeSensor in github.com/marcj/css-element-queries in a useEffect Commented Jan 25, 2021 at 11:39
  • 1
    You could however create a nest of 2 div. codesandbox.io/s/react-content-resized-detection-3f3gr . You're welcome. You'll want to check scrollHeight vs offsetHeight when you handle the onContentResized event. Let me know how you get on, and I'll make you a real answer if it helped. Commented Jan 25, 2021 at 12:26
  • 1
    I made some changes to better reflect usage and now pass a hasOverflow param in the onContentResized. Maybe that will help. codesandbox.io/s/react-content-resized-detection-3f3gr Commented Jan 25, 2021 at 13:13

1 Answer 1

3

It's not possible to know if arbitrary children are fully rendered without each one offering specialized callbacks. As such, it might be better to watch elements for size changes.

We can use ResizeObserver to our advantage here.

If we create a nested pair of div:

<div class="fixed_size_overflow_auto">
    <div>
        {children}
    </div>
</div>

making the outer div have fixed dimensions, we can listen for resize on the inner div. When we detect those resizes, we can calculate if the outer div has overflowed by comparing its offsetHeight to its scrollHeight.

Here is the idea, wrapped up in a component that can be styled using styled-components:

const DetectContentResizeElement: FC<{
  className?: string;
  onContentResized?: (v: { hasOverflow: boolean }) => void;
}> = ({ children, onContentResized, className }) => {

  const contentRef = useRef<HTMLDivElement>(null);
  const outerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!contentRef.current || !outerRef.current) {
      return;
    }

    const obs = new ResizeObserver(() => {
      const hasOverflow =
        (outerRef.current?.offsetHeight ?? 0) <
        (contentRef.current?.offsetHeight ?? 0);
      onContentResized?.({ hasOverflow });
    });

    obs.observe(contentRef.current);
    return () => obs.disconnect();
  }, [onContentResized]);

  return (
    <div className={className} ref={outerRef}>
      <div ref={contentRef}>{children}</div>
    </div>
  );
};

You can fix the size of this component by "subclassing" it with styled-components:

const FixedHeight = styled(DetectContentResizeElement)`
  height: 200px;
  width: 200px;
  border: solid 1px black;
  overflow: auto;
`;

so now you can use this container and get events that tell you when it overflowed:

  <FixedHeight
    onContentResized={({ hasOverflow }) =>
      console.log(`resized. hasOverflow: ${hasOverflow}`)
    }
  >
    <SomeChildElement />
  </FixedHeight>

See it in action in this codesandbox project (uses resize-observer-polyfill ponyfill for best compatibility)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.