ui icon indicating copy to clipboard operation
ui copied to clipboard

The content in ScrollArea doesn't scroll when using max-height

Open MukaiUshio opened this issue 2 years ago • 7 comments

The content in ScrollArea scrolls well when height is specified in className, but not when max-height is used.

here's the example

working

<ScrollArea className="min-w-full h-screen border-slate-200 border rounded-lg">
//content...(the height is larger than screen)
</ScrollArea>

not working

<ScrollArea className="min-w-full max-h-screen border-slate-200 border rounded-lg">
//content...(the height is larger than screen)
</ScrollArea>

MukaiUshio avatar May 04 '23 09:05 MukaiUshio

Just noticed that has well.

cmoleka avatar May 06 '23 18:05 cmoleka

I found a very bad solution but it works right now. Just need to set a height, detect the actual height of the content, and adapt it if it's lower than the max height.

import { Root as ScrollAreaRoot } from "@radix-ui/react-scroll-area"
...

const [scrollAreaHeight, setScrollAreaHeight] = useState<number>(200) // the max height
const scrollArea = useRef<React.ElementRef<typeof ScrollAreaRoot>>(null)
...

useEffect(() => {
  const textDiv = (
    document.querySelector(
      "[data-radix-scroll-area-viewport]"
    ) as HTMLDivElement // The viewport containing the content of scroll area
  )?.children[0] as HTMLDivElement // The actual content of the scroll area

  setScrollAreaHeight(textDiv?.offsetHeight < 200 ? textDiv?.offsetHeight : 200) // Set it to the actual height if it's lower than max height
}, [])
...

return (
  <ScrollArea
    ref={scrollArea}
    className={`h-[${scrollAreaHeight}px]`}
  >
    // The content
  </ScrollArea>
)

0xpolarzero avatar Jun 07 '23 07:06 0xpolarzero

Here is a solution that works with resizing. I would be happy if someone came up with better/css only solution.

const ScrollArea = React.forwardRef<
	React.ElementRef<typeof ScrollAreaPrimitive.Root>,
	React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, forwardedRef) => {
	const ref = React.useRef<HTMLDivElement>(null);

	React.useEffect(() => {
		const content = document.querySelector("[data-radix-scroll-area-viewport]")?.children[0] as HTMLElement | undefined;
		if (!content) return;

		const observer = new ResizeObserver((entries) => {
			const entry = entries[0].target as HTMLElement;
			if (ref.current) {
				// NOTE: This is a hack to fix the scroll area not resizing properly
				// when the content is smaller than the scroll area.
				ref.current.style.height = entry.offsetHeight + "px";
				ref.current.style.height =
					entry.offsetHeight < ref.current.offsetHeight
						? entry.offsetHeight + "px"
						: ref.current.offsetHeight + "px";
			}
		});

		observer.observe(content);

		return () => {
			observer.disconnect();
		};
	}, []);

	return (
		<ScrollAreaPrimitive.Root
			ref={composeRefs(forwardedRef, ref)}
			className={cn("relative overflow-hidden", className)}
			{...props}
		>
			<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
				{children}
			</ScrollAreaPrimitive.Viewport>
			<ScrollBar />
			<ScrollAreaPrimitive.Corner />
		</ScrollAreaPrimitive.Root>
	);
});

tobiasfoerg avatar Jun 21 '23 14:06 tobiasfoerg

Hey guys, can you confirm if works if you pass the max-h-* to the Viewport instead of the Root?. Thanks!

joaom00 avatar Jun 27 '23 20:06 joaom00

This worked for me

<ScrollArea>
  <div className="max-h-[20rem]">
    ... content
  </div>
</ScrollArea>

skibitsky avatar Jul 04 '23 05:07 skibitsky

This worked for me

<ScrollArea>
  <div className="max-h-[20rem]">
    ... content
  </div>
</ScrollArea>

This is it 👏! Thanks!

max-programming avatar Jul 12 '23 14:07 max-programming

set the components like this, use flex limit viewport height

const ScrollArea = React.forwardRef<
  React.ElementRef<typeof ScrollAreaPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
  <ScrollAreaPrimitive.Root
    className={classX('flex flex-col relative overflow-hidden', className)}
  >
    <ScrollAreaPrimitive.Viewport
      ref={ref}
      className="flex-grow w-full rounded-[inherit]"
      {...props}
    >
      {children}
    </ScrollAreaPrimitive.Viewport>
    <ScrollBar />
    <ScrollAreaPrimitive.Corner />
  </ScrollAreaPrimitive.Root>
))

this code works fine

<ScrollArea className="min-w-full max-h-[80vh] border-slate-200 border rounded-lg">
      <div className="h-[110vh]"></
</ScrollArea>

shaddollxz avatar Apr 18 '24 12:04 shaddollxz

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.

shadcn avatar Jul 02 '24 23:07 shadcn