Components

Components from other modules

Read time: 4 minutes

When we create a component as a function in a LiveView we gain access to it in our HEEx using <.function_name>. However if you need to use it in another LiveView you need to say the module name too. Create and run shared_component.exs:

Mix.install([
  {:liveview_playground, "~> 0.1.5"}
])

defmodule CustomRouter do
  use LiveviewPlaygroundWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
  end

  scope "/" do
    pipe_through :browser

    live "/", IndexLive, :index
    live "/other", OtherPageLive, :index
  end
end

defmodule IndexLive do
  use LiveviewPlaygroundWeb, :live_view

  def render(assigns) do
    ~H"""
    <.hero>IndexLive</.hero>
    <.link navigate={~p"/other"}>Go to other</.link>
    """
  end

  slot :inner_block, required: true

  def hero(assigns) do
    ~H"""
    <div class="bg-gray-800 text-white py-20">
      <div class="container mx-auto text-center">
        <h1 class="text-4xl font-bold"><%= render_slot(@inner_block) %></h1>
        <p class="mt-4 text-lg">My personal website</p>
        <.link
          class="mt-8 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
          navigate={~p"/other"}
        >
          Get Started
        </.link>
      </div>
    </div>
    """
  end
end

defmodule OtherPageLive do
  use LiveviewPlaygroundWeb, :live_view

  def render(assigns) do
    ~H"""
    <IndexLive.hero>OtherPageLive</IndexLive.hero>
    <.link navigate={~p"/"}>Go to home</.link>
    """
  end
end

LiveviewPlayground.start(router: CustomRouter, scripts: ["https://cdn.tailwindcss.com"])

For this example we created a simple Hero component (a component generally used to draw attention). To be able to use it in OtherPageLive we had to use the syntax <IndexLive.hero>OtherPageLive</IndexLive.hero>.

#Getting to know CoreComponents

In Phoenix projects when we have certain components that are useful in various parts of our system we choose to share them in a module called CoreComponents and import them. Create and run a file called core_components.exs:

Mix.install([
  {:liveview_playground, "~> 0.1.5"}
])

defmodule CustomRouter do
  use LiveviewPlaygroundWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
  end

  scope "/" do
    pipe_through :browser

    live "/", IndexLive, :index
    live "/other", OtherPageLive, :index
  end
end

defmodule CoreComponents do
  use LiveviewPlaygroundWeb, :html

  slot :inner_block, required: true

  def hero(assigns) do
    ~H"""
    <div class="bg-gray-800 text-white py-20">
      <div class="container mx-auto text-center">
        <h1 class="text-4xl font-bold"><%= render_slot(@inner_block) %></h1>
        <p class="mt-4 text-lg">My personal website</p>
        <.link
          class="mt-8 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
          navigate={~p"/other"}
        >
          Get Started
        </.link>
      </div>
    </div>
    """
  end
end

defmodule IndexLive do
  use LiveviewPlaygroundWeb, :live_view
  import CoreComponents

  def render(assigns) do
    ~H"""
    <.hero>IndexLive</.hero>
    <.link navigate={~p"/other"}>Go to other</.link>
    """
  end
end

defmodule OtherPageLive do
  use LiveviewPlaygroundWeb, :live_view
  import CoreComponents

  def render(assigns) do
    ~H"""
    <.hero>OtherPageLive</.hero>
    <.link navigate={~p"/"}>Go to home</.link>
    """
  end
end

LiveviewPlayground.start(router: CustomRouter, scripts: ["https://cdn.tailwindcss.com"])

Now our hero component lives in a module dedicated to useful application components. It is worth mentioning that our CoreComponents have a use LiveviewPlaygroundWeb, :html call to import several functions such as HEEx support and sigil_p for routes.

In each of our LiveViews we manually use import CoreComponents. In Elixir when you import a module you get all its functions so we can use <.hero> instead of <CoreComponents.hero> because the hero/1 function now is available in each LiveView.

CoreComponents in the real world

In this example we are creating a module called CoreComponents but in real Phoenix projects it would be called YourWebApp.CoreComponents and it would already be automatically generated and imported. We are just doing this manual exercise so you can understand better what advantages this architecture has.

#Recap!

  • You can use components from other modules using the <ModuleName.component_name> syntax.
  • If the component in question is used in a lot of places in the application consider placing it in your CoreComponents.
  • During classes we will manually build and import our CoreComponents but in the real world Phoenix already does that for you.

Feedback

Got any feedback about this page? Let us know!