Rendering multiple LiveView Streams with Infinite Scroll based on viewport size

I have a LiveView page in which I would like to render a stream of items differently depending on viewport size. Currently, I use Tailwind classes like hidden and lg:inline-table to render a <table> on wider viewports and lg:hidden and block to render a list of cards on narrow viewports. In order to render both lists within the same DOM, I need to give each element a unique identifier. This requires me to setup two streams pointed to the same data source and configured to generate DOM identifiers differently: stream(:rows) and stream(:cards).

Using two streams in this way works well until I want to use the InfiniteScroll hook. On LiveView version 0.19.3, using the phx-viewport-bottom attribute on both of the stream elements results in triggering more rows to be added as soon as a scroll action is detected. This is due to the hidden list element’s last child being higher up in the viewport. A small change to the onScroll event handler in the InfiniteScroll hook to exit early if the element is hidden (if (this.el.offsetParent === null) { return };) fixes the scroll behavior for the page and items aren’t loaded until the last child of the visible element is on the screen.

Have others run into similar issues? Does the proposed solution make sense or should I be considering other options? I’m happy to open a Pull Request with the aforementioned change, but I wanted to solicit ideas here first. Thank you!

1 Like