- Published on
- ← Blog
Build dynamic navs with current_page? (and conditional classes)
- Authors
- Name
- Harrison Broadbent
- @hrrsnbbnt
By combining the
current_page?
helper with dynamic classes, we can build a nav that's styled differently based on the page we're on. Here's an example —
Table of Contents
Nav bars. You've got one, I've got one — almost every Rails app has a nav.
I've finally built a nav I'm happy with, and I wanted to share it with you all! This nav combines the current_page? helper with dynamic classes (under the hood, the class_names helper).
The final result? Conditional styling based on the page we're on. In this example, we use this to style our "active" page with a red underline.
Before we get to the example, I want to look at the current_page?
helper, and how conditional classes work in our Rails views.
current_page?
helper
The current_page?
is a helper method defined inside ActionView::Helpers::UrlHelper
(view the source).
We pass it a path or URL, and it returns true
if we're on that page.
For example, if we open our Rails app and visit the root_path
of our app, current_path?(root_path)
will be true
.
The current_path?
helper takes a few more optional arguments, but we've covered the crux of it. I'm sure it has a wide range of uses, but I typically use it for adding dynamic styles to my UIs (like we're doing with this navbar).
class_names
helper)
Conditional classes (using the The class_names
helper (itself just an alias for ActionView::Helpers::TagHelper.token_list
, source) was introduced as part of Rails 6.1 to make conditionally applying classes in your views easier.
We can use it implicitly in our views like this —
# class-1 applied, class-2 not
<%= tag.p class: [
"class-1" : true,
"class-2" : false
] %>
# output
<p class="class-1"></p>
We can use the class_names
helper (implicitly) with any ActionView helper that accepts a class:
attribute (tag helpers like tag.p
, link_to
like below, and more). We can even use it inside ViewComponents!
The advantage of the class_names
helper is cleaner view code — rather than interpolating classes inside your views (<p class="<%= "class-1" if true %>">
), we let Rails handle everything.
Building a dynamic navbar
Here's the nav! Combining current_path?
with the class_names
helper (implicitly) inside our link_to
tag makes dynamically applying classes easy.
The first group of classes inside our link_to
are always applied. The second group are applied if we're on the current path (current_path?(...) == true
), otherwise the third group apply (!current_path?(...) == true
).
<% @nav_links = [
{ name: "Pricing", path: pricing_path },
{ name: "Components", path: components_path },
{ name: "Docs", path: documentation_path },
] %>
<% @nav_links.each do |link| %>
<%= link_to link[:name],
link[:path],
class: [
"border-b-2 px-1 hover:border-red-500",
"border-red-500": current_page?(link[:path]),
"border-transparent text-gray-700": !current_page?(link[:path]),
] %>
<% end %>
You can expand and adjust this as needed, but it's a perfect starting point for a simple, dynamic nav for your Ruby on Rails app.
Here's the same code packaged up as a ViewComponent. I've been diving into ViewComponents lately and I'm loving them. If you prefer regular partials though, you can use the code from above.
class Ui::Nav < ViewComponent::Base
def before_render
@nav_links = [
{name: "Pricing", path: pricing_path},
{name: "Components", path: components_path},
{name: "Docs", path: documentation_path},
]
end
erb_template <<~ERB
<nav>
<% @nav_links.each do |link| %>
<%= link_to link[:name],
link[:path],
class: [
"border-b-2 px-1 hover:border-red-500",
"border-red-500": current_page?(link[:path]),
"border-transparent text-gray-700": !current_page?(link[:path]),
] %>
<% end %>
</nav>
ERB
end
Note: We call
def before_render
instead ofdef initialize
since we need access to the path helpers. Learn more from the ViewComponent docs.
Conclusion
I hope you found this article useful! This dynamic nav is something I pulled out of RailsNotes UI, and initially started as a tweet. People seemed to enjoy it, so I thought I'd turn it into something less transient.
I also hope you've learned something new! The current_path?
helper is one I use all the time, and class_names
is also growing on me. Both are super handy!
Join 1050+ Ruby on Rails lovers
Join 1050+ Ruby on Rails lovers and get our weekly newsletter, no spam. Just interesting Rails articles, from here and around the web.