How to render two components under a single LiveComponent's management

I’m exploring a document editor using liveview. Currently I have a single liveview that renders a number of “sections” and each section has its on form that appears when the section is selected.

I’d like to support more state management for each section (e.g. lazy-loading some images when I start editing an image section), and I’ve been exploring LiveComponents for this.

Is it possible for a LiveComponent to be used to render more than 1 element? I’m not talking about having e.g. two tags in the root of the HEEX, I’m talking about having two distinct elements on the page that both link back to the same livecomponent.

Because: I need to support this pattern where I have the “view” of the section on the left which is always visible. And when a section is selected, the section editor also appears in an area on the right.

Alternative ideas would also be welcome.

I’m not sure whether you mean two instances of a LiveComponent module, or whether you mean a single instance that has multiple tags in the DOM in different places.

If you’re asking whether you can have more than once instance of a LiveComponent, the answer is yes - you can render as many as you want wherever you want. Give each one a different id and they will all have their own state.

If you mean a single LiveComponent instance with multiple tags in different places in the DOM, the answer is no - the LiveComponent’s render must be encompassed by a single tag. You could probably engage in some CSS trickery with position: fixed, but I wouldn’t.

Do also make sure you understand the difference between LiveViews, LiveComponents, and regular (function) Components:

  • LiveViews are a single process on the server-side which is connected (via WebSocket) to an element on the client. You can actually have more than one LiveView on a page.

  • LiveComponents exist within a LiveView (and therefore within its process), but they have their own state for the purposes of diff-tracking (which is handy for performance optimizations). They can also accept their own events, which is useful for factoring out a large LiveView app (otherwise a single file can get messy with all the event handlers).

  • (Function) Components are just functions, they have no state at all. You should use these most of the time.

I would probably need a more thorough description of your app to give better advice, but what you described doesn’t necessarily require LiveComponents at all. There’s nothing stopping you from lazy-loading the images within the main LiveView. You should split the app into LiveComponents when it grows too large (or when you need to optimize performance in the case of a large collection - the separate diff-tracking helps to prevent large diffs being sent over the wire).

1 Like

Thanks for the thoughtful reply @garrison

The key thing is knowing that a livecomponent that is in charge of many elements is not supported. I want to segregate a bunch of heavy state management and that state drives two elements in different parts of the hierarchy.

I was considering the option of something like a liveview with multiple render functions, but I get that’s not supported now.

I may end up using the livecomponent to do all the heavy work needed (in this case, doing lots of rich media navigation to select images etc that go into the main document structure), and then when that’s done, I will simply send a message back to the parent liveview (which I know is self() in this case) and update the LV’s state with the result of all the data fetching and interaction that went into choosing the image.

1 Like

I also feel I may not have fully understood yet, but wanted to note that all those 3 primitives are composable. You can have a LiveComponent render other LiveComponents or functions components or even other LiveViews.

Another consideration when building complex hierarchies will be data flow and sources of truth. There’s a guide in this respect: Phoenix.LiveComponent — Phoenix LiveView v0.20.17

1 Like

Multiple live views on one page?! I had no idea that is possible, are you able to point to an example of that @garrison?

I’m currently working with a live view that has several live components (a set of tabs that need a tiny bit of awareness of each other)

But it’s starting to feel messy. I’d like to avoid multiple routes, so the idea that I could use multiple live views under one route sounds very intriguing!

Thanks

You would use live_render/3. There are some basic usage examples in the docs on how to render within another LiveView.

1 Like

LiveBeats uses live_render/3 to render the player across pages.