phoenix_live_view icon indicating copy to clipboard operation
phoenix_live_view copied to clipboard

phx-viewport-botton don't fire events after parent element x-scroll is used

Open paulo-silva opened this issue 5 months ago • 1 comments

Environment

  • Elixir version (elixir -v): 1.18.3
  • Phoenix version (mix deps): 1.7.21
  • Phoenix LiveView version (mix deps): 1.0.17
  • Operating system: macOS 15.5
  • Browsers you attempted to reproduce this bug on (the more the merrier): Arc (Chromium)
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Actual behavior

Issue with phx-viewport-bottom, when the user has x and y overflow. I noticed that if the user scrolls horizontally and then tries to scroll down to load the following pages, for example, the handle_event stops from being fired. This works when the horizontal scroll is in the element with phx-viewport-bottom, but it doesn't work if the parent has a horizontal scroll, for example.

Here is a small project to exemplify the issue: https://github.com/paulo-silva/lv-phx-viewport-bottom-issue

Works when using horizontal scroll on the element having phx-viewport-bottom:

https://github.com/user-attachments/assets/e4c9a3d7-85b5-4435-83de-ad70da33c9cc

Does not work when using horizontal scroll from parent element and then scrolling down the element having phx-viewport-bottom:

https://github.com/user-attachments/assets/51fd827b-c790-479f-a4f5-c2a46eddfb5e

Expected behavior

The phx-viewport-bottom should fire the event whenever user scroll down the element having it, when it reaches the bottom.

paulo-silva avatar Jul 16 '25 15:07 paulo-silva

https://github.com/phoenixframework/phoenix_live_view/blob/b304ad5e97bfa98d4907afb79f503ccc5dba3cce/assets/js/phoenix_live_view/hooks.js#L137-L144

I believe it's this line of code here Math.ceil(rect.left) >= 0 that prevents the isAtViewportBottom from returning true on an element that has horizontal scroll. When the element with phx-viewport-bottom is scrolled by the user to the right, rect.left ends up being negative (despite the element clearly still being in the viewport), so the whole function returns false. The result is broken infinite pagination.

Perhaps the .left check was an attempt to verify the element is even in the viewport at all? It's not exactly clear

qq99 avatar Sep 04 '25 14:09 qq99