How to get Twitter-Bootstrap navigation to show active link?
Asked Answered
D

23

108

I'm not understanding how Twitter Bootstrap does active links for the navigation. If I have a regular navigation like this (with ruby on rails linking):

<ul class="nav">
  <li class="active"> <a href="/link">Link</a> </li>
  <li class=""> <a href="/link">Link</a> </li>
  <li class=""> <a href="/link">Link</a> </li>        
</ul>

How do I keep it active based on the link clicked?

Droplet answered 26/3, 2012 at 20:18 Comment(1)
FYI: I use the active_link_to gem and specify {:wrap_class => :li}. This will create: <li class='active'>...</li> when the REQUEST_URI matches the HREF value...Saiz
F
98

Just made an answer on the very same question here Twitter Bootstrap Pills with Rails 3.2.2

<ul class="nav">
  <li class="<%= 'active' if params[:controller] == 'controller1' %>"> <a href="/link">Link</a> </li>
  <li class="<%= 'active' if params[:controller] == 'controller2' %>"> <a href="/link">Link</a> </li>
  <li class="<%= 'active' if params[:controller] == 'controller3' %>"> <a href="/link">Link</a> </li>        
</ul>
Flowerdeluce answered 26/3, 2012 at 20:27 Comment(6)
I think the idea is correct here, but going directly to the params hash seems like a bad idea. Likewise for repeating the same code over and over. I would recommend at least using the current_page? method to check the current controller/action, and would also move the code into a helper to avoid the code repetition.Antic
I wonder how do I write the same in haml. Converting to haml doesn't work for me. Or perhaps I'm wrong somewhereLambdoid
HAML implementation %li{:class => "#{'active' if current_page?(root_path)}"}=link_to "Home", root_path Whereby
Is there an elegant way of making this work with friendly_id gem without doing db requests?Talkative
Rails docs recommends the use of controller_name and action_name helpers instead of accessing them from the params hash.Telegony
Or another one for HAML: %li{class: params[:controller].nil? ? 'active' : ''}= link_to 'Home', root_pathParceling
C
175

You can use something like (very similar to what @phil mentioned, but a little shorter):

<ul class="nav">
  <li class="<%= 'active' if current_page?(root_path) %>"><%= link_to "Home", root_path %></li>
  <li class="<%= 'active' if current_page?(about_path) %>"><%= link_to "About", about_path %></li>
  <li class="<%= 'active' if current_page?(contact_path) %>"><%= link_to "Contact", contact_path %></li>
</ul>
Cabalist answered 27/7, 2012 at 14:44 Comment(4)
doesn't work if you have subnavigation. The path changes but you're in the same section.. makes sense?Fingered
yes, correct, if you want to highlight a menu item no matter what method you are running inside the same controller, you could use @Pierre solution: 'active' if params[:controller] == 'controller1'Cabalist
How can I add more paths or a specific path like user_*_path in <%= 'active' if current_page?(root_path) %> ?Enfranchise
How would you add more than one path to make the menu item active? For instance, if you have several items in a dropdown that are components of the same menu item, and you'd like to make the menu item active when you're on any of the pages found in the dropdown menu? Please let us know as soon as possible.Sirree
F
98

Just made an answer on the very same question here Twitter Bootstrap Pills with Rails 3.2.2

<ul class="nav">
  <li class="<%= 'active' if params[:controller] == 'controller1' %>"> <a href="/link">Link</a> </li>
  <li class="<%= 'active' if params[:controller] == 'controller2' %>"> <a href="/link">Link</a> </li>
  <li class="<%= 'active' if params[:controller] == 'controller3' %>"> <a href="/link">Link</a> </li>        
</ul>
Flowerdeluce answered 26/3, 2012 at 20:27 Comment(6)
I think the idea is correct here, but going directly to the params hash seems like a bad idea. Likewise for repeating the same code over and over. I would recommend at least using the current_page? method to check the current controller/action, and would also move the code into a helper to avoid the code repetition.Antic
I wonder how do I write the same in haml. Converting to haml doesn't work for me. Or perhaps I'm wrong somewhereLambdoid
HAML implementation %li{:class => "#{'active' if current_page?(root_path)}"}=link_to "Home", root_path Whereby
Is there an elegant way of making this work with friendly_id gem without doing db requests?Talkative
Rails docs recommends the use of controller_name and action_name helpers instead of accessing them from the params hash.Telegony
Or another one for HAML: %li{class: params[:controller].nil? ? 'active' : ''}= link_to 'Home', root_pathParceling
C
46

https://github.com/twg/active_link_to

<%= active_link_to 'Users', users_path, :wrap_tag => :li %>

#=> <li class="active"><a href="/users">Users</a></li>

Chivalric answered 4/8, 2012 at 17:48 Comment(2)
Love it. Why rewrite the wheel?Mesics
This should really be the way to go...Unless you don't want to pull in another dependency.Valina
M
34

I used a helper to implement this in the style of Rails' form helpers.

In a helper (e.g. app/helpers/ApplicationHelper.rb):

def nav_bar
  content_tag(:ul, class: "nav navbar-nav") do
    yield
  end
end

def nav_link(text, path)
  options = current_page?(path) ? { class: "active" } : {}
  content_tag(:li, options) do
    link_to text, path
  end
end

Then, in a view (e.g. app/views/layouts/application.html.erb):

<%= nav_bar do %>
  <%= nav_link 'Home', root_path %>
  <%= nav_link 'Posts', posts_path %>
  <%= nav_link 'Users', users_path %>
<% end %>

This example produces (when on the 'users' page):

<ul class="nav navbar-nav">
  <li><a href="/">Home</a></li>
  <li><a href="/posts">Posts</a></li>
  <li class="active"><a href="/users">Users</a></li>
</ul>
Mopup answered 7/6, 2014 at 8:30 Comment(2)
This is great! Thanks!Gormandize
I like this idea, however I'd add a third argument to the nav_link function called html={} that's then passed to link_to. That way you can pass an html hash to nav_link the same way you'd use link_to normally.Cardamom
C
22

Use this instead to select active link in nav based on the current route without server code:

    $(document).ready(function () {
        $('a[href="' + this.location.pathname + '"]').parent().addClass('active');
    });
Curly answered 14/11, 2012 at 8:46 Comment(2)
This is the best solution cause it works with dropdown menus as well, and I include the line $('li.active').closest('.dropdown').addClass('active'); to highlight the parent menu too.Extraterrestrial
how to change it to apply for sub-pages also? like example.com/home will work. I need link "Home" to be active in case of example.com/home/page also.Anjelicaanjou
V
11

I've found success using the logical and (&&) in haml:

%ul.nav
  %li{class: current_page?(events_path) && 'active'}
    = link_to "Events", events_path
  %li{class: current_page?(about_path) && 'active'}
    = link_to "About Us", about_path
Vestiary answered 15/1, 2013 at 16:58 Comment(0)
I
5

For each link:

<% if current_page?(home_path) -%><li class="active"><% else -%><li><% end -%>
  <%= link_to 'Home', home_path %>
</li>

or even

<li <% if current_page?(home_path) -%>class="active"<% end -%>>
  <%= link_to 'Home', home_path %>
</li>
Interjection answered 2/5, 2012 at 12:10 Comment(0)
H
3

not sure if you are asking about how the twitter bootstrap css is used, or the rails side. I'm assuming the rails side.

if so checkout the #link_to_if method or the #link_to_unless_current method

Harding answered 26/3, 2012 at 20:20 Comment(0)
C
3

Today I had the same question/problem but with an other approach for the solution. I create a helper function in application_helper.rb:

def navMainAktiv(actionName)
    if params[:action] == actionName    
    "active"
    end
end

and the link looks like this:

<li class="<%= navMainAktiv('about')%>"><%= link_to "About", about_path %></li>

You can replace params[:action] with params[:controller] and set your controller name in the link.

Coffman answered 7/6, 2012 at 2:1 Comment(0)
S
3

Basic, No Helper

<%= content_tag(:li, class: ('active' if request.path == '/contact')) do %>
    <%= link_to 'Contact', '/contact' %>
<% end %>

I use this since I have more than one class -

<%= content_tag(:li, class: (request.path == '/contact' ? 'active black' : 'black')) do %>
    <%= link_to 'Contact', '/contact' %>
<% end %>
Sulphathiazole answered 21/6, 2017 at 14:26 Comment(1)
This will work for any sub navigation also...just use the parent request path in the sub link.Sulphathiazole
E
2

I use this for each li:

<li><%= link_to_unless_current('Home', root_path) { link_to('Home', root_path, class: 'active') } %></li>

Erich answered 24/6, 2013 at 14:3 Comment(1)
Class needs to be set for li not aStricture
G
2

You may define a helper method in application_helper.rb

def create_link(text, path)
  class_name = current_page?(path) ? 'active' : ''

  content_tag(:li, class: class_name) do
    link_to text, path
  end
end

Now you can use like:

create_link 'xyz', any_path which would render as

<li class="active">
  <a href="/any">xyz</a>
</li>

Hope it helps!

Gully answered 20/10, 2015 at 8:48 Comment(0)
T
2

Here's what I did:

I created a ViewsHelper and included in ApplicationController:

include ViewsHelper

Inside ViewsHelper I created a simple method like this:

def page_state(path)
  current_page?(path) ? 'active' : ''
end

In my view I do this:

<li class="<%= page_state(foobar_path) %>"><%= link_to 'Foobars', foobar_path %></li>
Tonetic answered 16/9, 2017 at 15:35 Comment(0)
W
1

You should do it yourself by manipulating CSS classes. That is, if a user clicks on some link, then do something (target action), set previous link inactive and new link active.

If your links take you to the server (that is, make page reload), then you can just render active link correctly on the server. Otherwise, if you're doing some client-side stuff (switching tab panes or whatever), you have to use javascript.

Whittle answered 26/3, 2012 at 20:20 Comment(0)
D
1

you could use tabulous for the links

article here on how to combine tabulous with twitter bootstrap and rails 3.x

Dvinsk answered 26/3, 2012 at 20:33 Comment(0)
R
1

I wrote simple helper method using build in view helper current_page? when you can specify custom class name in html_options hash.

def active_link_to(name = nil, options = nil, html_options = nil, &block)
  active_class = html_options[:active] || "active"
  html_options.delete(:active)
  html_options[:class] = "#{html_options[:class]} #{active_class}" if current_page?(options)
  link_to(name, options, html_options, &block)
end

Examples (when you are on root_path route):

<%= active_link_to "Main", root_path %>
# <a href="/" class="active">Main</a>

<%= active_link_to "Main", root_path, class: "bordered" %>
# <a href="/" class="bordered active">Main</a>

<%= active_link_to "Main", root_path, class: "bordered", active: "disabled" %>
# <a href="/" class="bordered disabled">Main</a>
Rectangle answered 31/10, 2013 at 12:17 Comment(0)
P
1

Many of the answers here have things that will work, or partial answers. I combined a bunch of things to make this rails helper method I use:

# helper to make bootstrap3 nav-pill <li>'s with links in them, that have
# proper 'active' class if active. 
#
# the current pill will have 'active' tag on the <li>
#
# html_options param will apply to <li>, not <a>. 
#
# can pass block which will be given to `link_to` as normal. 
def bootstrap_pill_link_to(label, link_params, html_options = {})
  current = current_page?(link_params)

  if current
    html_options[:class] ||= ""
    html_options[:class] << " active "
  end

  content_tag(:li, html_options) do
    link_to(label, link_params)
  end      
end

It could be made even fancier with argument checking to support &block on the link_to etc.

Perjury answered 12/12, 2013 at 16:7 Comment(0)
D
1

Many answers already, but here is what I wrote to get Bootstrap Icons working with active link. Hope It will help someone

This helper will give you:

  1. li element with link containing custom text
  2. Optional Bootstrap3 Icon
  3. will turn active when you're on the right page

Put this in your application_helper.rb

def nav_link(link_text, link_path, icon='')
  class_name = current_page?(link_path) ? 'active' : ''
  icon_class = "glyphicon glyphicon-" + icon

  content_tag(:li, :class => class_name) do
    (class_name == '') ? (link_to content_tag(:span, " "+link_text, class: icon_class), link_path)
    : (link_to content_tag(:span, " "+link_text, class: icon_class), '#')
  end
end

And use link:

<%= nav_link 'Home', root_path, 'home'  %>

Last argument is optional - it will add icon to the link. Use names of glyph icons. If you want icon with no text:

    <%= nav_link '', root_path, 'home'  %>
Dihedral answered 19/6, 2014 at 7:23 Comment(0)
B
0

You sound like you need to implement a navigation system. If it's complex, it might get pretty ugly and pretty fast.

In this case, you might want to use a plugin that can handle that. You could use navigasmic or simple navigation (I would recommend navigasmic because it keeps the main layer in a view, where it belongs, and not in some configuration)

Buff answered 26/3, 2012 at 20:25 Comment(0)
L
0

Shortest code 

This deals with BOTH nav, and sub nav list elements. You can pass either an array a single path and will deal with both.

application_helper

# Active page method
def ap(p:);'active' if p.class == Array ? p.map{|m| current_page? m}.any? : (current_page? p) end

view (html.erb)

<ul class="nav navbar-nav">
  <li class="<%= ap p: home_path %>">Home</li>
  <li class="<%= ap p: account_path %>">Account</li>

  <li class="dropdown <%= ap p: [users_path, new_user_path] %>">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Users</a>
    <ul class="dropdown-menu" role="menu">
      <li class="<%= ap p: users_path %>">Users</li>
      <li class="<%= ap p: new_user_path %>">Add user</li>
    </ul>
  </li>
</ul>
Lydon answered 22/3, 2016 at 10:34 Comment(0)
R
0

Using ruby on Sinatra ..

I m using bootstrap bare theme, here is the sample navbar code. Note the class name of the element -> .nav - as this is referred in java script.

/ Collect the nav links, forms, and other content for toggling
    #bs-example-navbar-collapse-1.collapse.navbar-collapse
      %ul.nav.navbar-nav
        %li
          %a{:href => "/demo/one"} Page One
        %li
          %a{:href => "/demo/two"} Page Two
        %li
          %a{:href => "/demo/three"} Page Three

in the view page (or partial) add this :javascript, this needs to be executed every time page loads.

haml view snippet ->

- content_for :javascript do
  :javascript
      $(function () {
          $.each($('.nav').find('li'), function() {
              $(this).toggleClass('active',
                  $(this).find('a').attr('href') == window.location.pathname);
          });
      });

In the javascript debugger make sure you have value of 'href' attribute matches with window.location.pathname. This is slightly different than the solution by @Zitrax which helped me fixing my issue.

Ravenous answered 2/6, 2016 at 22:36 Comment(0)
G
0
  def active_navigation?(controllers_name, actions_name)
   'active' if controllers_name.include?(controller_name) && actions_name.include?(action_name)
  end

slim

li class=(active_navigation?(['events'], ['index', 'show'])) = link_to t('navbar.events'), events_path
Gypsophila answered 18/12, 2017 at 12:11 Comment(0)
B
0

This worked for me:

          <li class="nav-item <%= 'active' if current_page?(root_path) %>" >
            <%= link_to 'Home', root_path, class:"nav-link"%>
          </li>
          <li class="nav-item <%= 'active' if current_page?(tools_path) %>" >
            <%= link_to 'Tools', tools_path, class:"nav-link" %>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Request a new tool</a>
          </li>
          <li class="nav-item <%= 'active' if current_page?(home_about_path) %>" >
            <%= link_to 'About us', home_about_path, class:"nav-link"%>
          </li>

The code inside the <%= %> is just ruby, and the = means that the result of that code will be displayed on the HTML.Do this for every option you want to add in your navbar and it should work fine.

Borecole answered 5/1, 2021 at 18:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.