How to get the active route and update classes in a navigation bar?

I have a navigation bar in my web app. I need to update the active route link with css classes to show that it’s the active route.

My current approach is as follows:
In my NavigationView I have a helper function like this:


defmodule MyAppWeb.NavigationView do
  use MyAppWeb, :view
  
  def get_link_classes(conn, link) do
    classes = ["common-link-class"]
    
    classes = 
    if get_current_path(conn) == link do
      ["active-link-class" | classes]
    else
      classes
    end
    
    Enum.join(classes, " ")
  end
  
  defp get_current_path(conn) do
    conn
    |> Map.get(:request_path)
    |> String.split(~r/\//)
    |> Enum.at(1)
  end
end

The in my markup I use the helper function as follows:

<ul>
  <li>
    <%= link "Home", to: Routes.page_path(@conn, :index), class: get_link_classes(@conn, "") %>
  </li>
  <li>
    <%= link "Blog", to: Routes.blog_path(@conn, :index), class: get_link_classes(@conn, "blog")%>
  </li>
  <li>
    <%= link "About Me", to: Routes.blog_path(@conn, :index), class: get_link_classes(@conn, "about") %>
  </li>
</ul>

Is there a better approach to get the active link?

1 Like

One idea would be to wrap it with your own helper like so:

<%= my_link "Home", to: Routes.page_path(@conn, :index) %>
3 Likes

I’m personally using phoenix_active_link package. Has a bunch of options like inclusivity, exclusivity, exact match, regex options etc. It works for simple cases, but also for more complex scenarios, like a main menu with a sub-menu where you still want to show which item is active from the main menu.

2 Likes

I know this is old, but I wanted to share a straightforward approach on defining the classes using an alternative syntax:

<.link
  href={~p"/stores/#{@store}/products"}
  class={["tab", @active == :products && "tab-active"]}
>
  Products
</.link>

I’ve explained it in details in this blog post