Cannot convert component ... to HTML - A component must always be returned directly as part of a LiveView template

Hi,

i’ve create as scaffold with “mix phx.gen.auth”

i want to extend root.html.heex by two liveview-components
to create some kind of ‘container’ in which the router-content (@inner_content) in the center:

          ..............................................                                        
          .                                            .                                        
          .     root.html.heex                .                                        
          .                                            .                                        
          ..............................................                                        
          .      live-component-header  .                                        
          .    *************************                                         
          .                                            .                                        
          ..                                         ...                                        
          ..                                         ...                                        
          ..                                       ...                                        
          ..    @inner_content            ....                                       
          ..                                         ....                                       
          ..                                         ....                                       
          ..                                         ....                                       
          ..                                         ....                                       
          ..                                         ....                                       
          ..                                         .. .                                       
          ..                                         .. .                                       
          ..                                         .. .                                       
          ..                                         .. .                                       
          ..                                         .. .                                       
          ..                                         .. .                                       
          ..                                         .. .                                       
          ............................................. .                                       
          .    live-component-footer      .                                       
          ...............................................                                       

unfortunatelly, i cannot use the live-components in root.html.heex:

<div class="flex grow-1 shrink-1 basis-full flex-col">
        <div>
          <.live_component module={LiveWeb.HeaderComponent} id="header" />
        </div>
        <div>
          {@inner_content}
        </div>
        <div>
          <.live_component module={LiveWeb.FooterComponent} id="footer" />
        </div>
      </div>

Any hint is very appreciated.
Many thanks in advance.
regards
jensu

Hello and welcome!

Yes, you cannot use LiveComponents in the root layout as it is only rendered once the dead render and therefore does not have access to a @socket. This is documented here. You can, however, use them in app.html.heex which is rendered once the socket has connected.

The presence of <.live_title> is a bit confusing for sure but this is treated specially by the framework.

hi,

thanks a lot!

I’ve now adjusted my app.html.heex accordingly.
Unfortunatelly “:app” idoes not get used in the default generated router.ex.

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {TimeTrackerLiveWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :fetch_current_user
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", TimeTrackerLiveWeb do
    pipe_through :browser

    get "/", PageController, :home
  end

I’ve tried:

 plug :put_root_layout, html: {LiveWeb.Layouts, :app}

but that leads to the same error :frowning:

Any hint is very appreciated.
Many thanks in advance.
regards
jensu

app.html.heex already exists, you don’t have to do anything. All you did here was set app.html.heex as the root layout :slight_smile:

Both the root and app layouts are always rendered. Where you set the app layout is in lib/<my_app>_web.ex. Look for:

  def live_view do
    quote do
      use Phoenix.LiveView,
        layout: {Myapp[Web.Layouts, :app} # <-- here

      unquote(html_helpers())
    end
  end

You don’t have to change anything, just showing you where it is set.

Thanks a lot!

I think i got it:

a) root.html.heex loads app.html.heex
b) app.html.heex is meant to be used for a “container” (e.g.: header, footer)
c) in order to use the ‘container’ (app.html.heex) the custom live view (inside @inner_content of app.html.heex) needs to either implicitly rely on app.html.heex or explicitly rely on app.html.heex:

quote do
      use Phoenix.LiveView,
        layout: {Myapp[Web.Layouts, :app} # <-- here

      unquote(html_helpers())
    end

again, thanks a lot!