How To Create Tabs in Phoenix LiveView

Tracey Onim
3 min readMay 30, 2022

--

LiveView has been one of the exciting library that developers can use to make interactive applications without Javascript.

In this article, I will show you how you can create a tab using LiveView feature Phoenix.LiveView.JS . This feature was added in LiveView v0.17.0, it provides commands for executing JS utility operations on the client.

Let’s begin:

In our template we are going to add the following:

<a phx-click={JS.show(to: "#one") |> JS.push("switch_tab", value: %{tab: "one"})}>show one</a>
|
<a phx-click={JS.show(to: "#two") |> JS.push("switch_tab", value: %{tab: "two"})}>show two</a>
|
<a phx-click={JS.show(to: "#three") |> JS.push("switch_tab", value: %{tab: "three"})}>show three</a>
<%= if @tab == "one" do %>
<.tab_one/>
<% end %>
<%= if
@tab == "two" do %>
<.tab_two/>
<% end %>
<%= if
@tab == "three" do %>
<.tab_three/>
<% end %>

In the anchor tag, I have used a phx-click binding this is because LiveView bindings support a JS command interface via Phoenix.LiveView.JS module which allows you to specify utility operations that execute on the client when firing phx-binding events.

Here we want to show the content of each tab when clicked. Therefore we are going to use the JS show and push commands.

i) show command is used to display the content in each tab

ii) push command is used to push an event to the server where the socket will be updated so that the user can switch from one tab to another.

The show/1 passed has one argument which is the :to option that points to the DOM containing the content to display. In my case I have specified the DOM ID.

The push command has been passed with 3 arguments, that is the piped js struct , event name(“switch_tab”) and an option(:value which specifies the map of values to send to the server).

In addition, I have added an if statement whereby a function component defined in the server will be invoked only if the tab clicked matches.

Lets go ahead to the server side and implement the following:

defmodule SampleWeb.SampleLive do
use SampleWeb, :live_view
alias Phoenix.LiveView.JS
def mount(_params, _session, socket) do
{:ok, assign(socket, tab: "one")}
end
def handle_event("switch_tab", %{"tab" => tab}, socket) do
{:noreply, assign(socket, tab: tab)}
end
def tab_one(assigns) do
~H"""
<p id="one">tab one displayed</p>
"""
end
def tab_two(assigns) do
~H"""
<p id="two">tab two displayed</p>
"""
end
def tab_three(assigns) do
~H"""
<p id="three">tab three displayed</p>
"""
end
end

Here I have aliased Phoenix.LiveView.JS, so that we can use its functions.

Notice that in our mount/3, I have added a tab assign and give it the value “one” which points to the first tab.This is because, we want tab one to be the default tab whereby, when the user lands on the page they can see the contents inside the tab.

I have also handled the “switch_tab” event which updates the assign tab with the value of the tab clicked. For example , if tab two is clicked, a push event will be sent to the server with this map value (%{“tab” => “two”}).

Inside our server, I have also defined three function components that is tab_one/1 , tab_two/1 and tab_three/1 which contains the content of each tab.

In the browser you should see something similar to this:

Now that you have had a glimpse of what LiveView can do, Ihope you will find this blog helpful and it will guide you in creating complex interactive tabs.

Happy codding!!!

--

--

Tracey Onim

Backend software developer, Programming with Elixir/Phoenix/LiveView. Community organiser at ElixirKenya & ElixirConfAfr