58

Using twitter bootstrap, and I need to initiate active class to the li portion of the main nav. Automagically. We use php not ruby.

Sample nav :

<ul class="nav">
    <li><a href="/">Home</a></li>
    <li><a href="/forums">Forums</a></li>
    <li><a href="/blog">Blog</a></li>
    <li><a href="/faqs.php">FAQ's</a></li>
    <li><a href="/item.php">Item</a></li>
    <li><a href="/create.php">Create</a></li>
</ul>

Bootstrap code is as follows:

<li class="active"><a href="/">Home</a></li>

So just need to figure out how to append the class active to the current page. Have looked thru nearly every answer on Stack, with no real joy.

I had played with this:

/*menu handler*/
$(function(){
    var url = window.location.pathname;  
    var activePage = url.substring(url.lastIndexOf('/')+1);
    $('.nav li a').each(function(){  
        var currentPage = this.href.substring(this.href.lastIndexOf('/')+1);

        if (activePage == currentPage) {
            $(this).parent().addClass('active'); 
        } 
    });
})

But no joy.

Alex Weitz
  • 3,199
  • 4
  • 34
  • 57
422
  • 5,714
  • 23
  • 83
  • 139
  • possible duplicate of [How to get Twitter-Bootstrap navigation to show active link?](http://stackoverflow.com/questions/9879169/how-to-get-twitter-bootstrap-navigation-to-show-active-link) – KatieK Jan 25 '13 at 16:55
  • That question is Ruby though. –  Dec 18 '16 at 12:47

16 Answers16

130

For Bootstrap 3:

var url = window.location;
// Will only work if string in href matches with location
$('ul.nav a[href="'+ url +'"]').parent().addClass('active');

// Will also work for relative and absolute hrefs
$('ul.nav a').filter(function() {
    return this.href == url;
}).parent().addClass('active');

Update

For Bootstrap 4:

var url = window.location;
// Will only work if string in href matches with location
$('ul.navbar-nav a[href="'+ url +'"]').parent().addClass('active');

// Will also work for relative and absolute hrefs
$('ul.navbar-nav a').filter(function() {
    return this.href == url;
}).parent().addClass('active');
Imtiaz
  • 2,484
  • 2
  • 26
  • 32
  • Works perfectly with my MVC – Sharpless512 Jul 08 '13 at 15:46
  • 1
    Old question but i just jump here, what if i have a dropdown? and children href don't match parent but i wanna set parent as active – DJ22T Nov 17 '14 at 03:54
  • 2
    @DannyG - wouldn't you just add something like this to the end of code? ".parent().parent().addClass('active');" – jmotes Jan 17 '15 at 04:00
  • Works well, thanks. But what's the technicals as to why the two statements with addClass() needed? And not one? – belteshazzar Mar 15 '16 at 09:48
  • The comments in the code blocks will give you enough details. The first one is for complete URLs and the second one is for relative URLs – Imtiaz Mar 17 '16 at 16:58
  • Thanks a lot, It's simple and clean. I thought I have to work with cookie! – Majid Basirati Sep 02 '16 at 11:45
  • Not sure where I'd add this? –  Dec 18 '16 at 12:48
  • After you've loaded the jquery library. You wrap the code in the answer around a tag. – Imtiaz Dec 19 '16 at 06:38
  • @DannyG did u get how to set active in the parent for dropdown? can u help me? – Rian Mar 22 '17 at 01:53
  • This works perfectly with MVC. But you also if (window.location.search!='') {url += window.location.search;} for parameters and add .... .addClass('active').closest('.has-treeview').addClass('menu-open'); for opening menu trees. – macmuri May 10 '21 at 22:26
37

We managed to fix in the end:

/*menu handler*/
$(function(){
  function stripTrailingSlash(str) {
    if(str.substr(-1) == '/') {
      return str.substr(0, str.length - 1);
    }
    return str;
  }

  var url = window.location.pathname;  
  var activePage = stripTrailingSlash(url);

  $('.nav li a').each(function(){  
    var currentPage = stripTrailingSlash($(this).attr('href'));

    if (activePage == currentPage) {
      $(this).parent().addClass('active'); 
    } 
  });
});
Jay Truluck
  • 1,509
  • 10
  • 17
422
  • 5,714
  • 23
  • 83
  • 139
30

You don't really need any JavaScript with Bootstrap:

 <ul class="nav">
     <li><a data-target="#" data-toggle="pill" href="#accounts">Accounts</a></li>
     <li><a data-target="#" data-toggle="pill" href="#users">Users</a></li>
 </ul>

To do more tasks after the menu item is selected you need JS as explained by other posts here.

Hope this helps.

Kam
  • 517
  • 6
  • 7
13

if you put

data-toggle="pill"

in the tag it should work automatically.

http://twitter.github.com/bootstrap/javascript.html#tabs

read under Markup

user2045474
  • 135
  • 1
  • 9
10

This did the job for me including active main dropdowns and the active childrens (thanks to 422):

$(document).ready(function () {
    var url = window.location;
    // Will only work if string in href matches with location
    $('ul.nav a[href="' + url + '"]').parent().addClass('active');

    // Will also work for relative and absolute hrefs
    $('ul.nav a').filter(function () {
        return this.href == url;
    }).parent().addClass('active').parent().parent().addClass('active');
});
Alex Weitz
  • 3,199
  • 4
  • 34
  • 57
Sebastian Viereck
  • 5,455
  • 53
  • 53
8

If you are using an MVC framework with routes and actions:

$(document).ready(function () {
    $('a[href="' + this.location.pathname + '"]').parent().addClass('active');
});

As illustrated in this answer by Christian Landgren: https://stackoverflow.com/a/13375529/101662

Community
  • 1
  • 1
Oliver
  • 35,233
  • 12
  • 66
  • 78
6

Try this.

// Remove active for all items.
$('.page-sidebar-menu li').removeClass('active');

// highlight submenu item
$('li a[href="' + this.location.pathname + '"]').parent().addClass('active');

// Highlight parent menu item.
$('ul a[href="' + this.location.pathname + '"]').parents('li').addClass('active');
Alex Weitz
  • 3,199
  • 4
  • 34
  • 57
Durga Prasad
  • 333
  • 2
  • 6
  • 16
3

This works fine for me. It marks both simple nav elements and dropdown nav elements as active.

$(document).ready(function () {
   var url = window.location;

   $('ul.nav a[href="' + this.location.pathname + '"]').parent().addClass('active');

   $('ul.nav a').filter(function() {
      return this.href == url;
   }).parent().parent().parent().addClass('active');
});

Passing this.location.pathname to $('ul.nav a[href="'...'"]') marks also simple nav elements. Passing url did'nt work for me.

Ilker Cat
  • 1,862
  • 23
  • 17
2

Just in case you are using Boostrap in Angulajs: this is a simple directive that works for me (because data-toggle cited by Kam is not included in Angular-ui). Hope can help.

app.directive("myDataToggle", function(){
    function link(scope, element, attrs) {
        var e = angular.element(element);
        e.on('click', function(){
            e.parent().parent().children().removeClass('active');
            e.parent().addClass("active");
        })
    }
    return {
        restrict: 'A',
        link: link
    };
});

<ul class="nav nav-sidebar">
    <li><a href="#/page1" my-data-toggle>Page1</a></li>
    <li><a href="#/page2" my-data-toggle>Page2</a></li>
    <li><a href="#/page3" my-data-toggle>Page3</a></li>
</ul>
mvillegas
  • 123
  • 6
1

The solution is simple and there is no need for server side or ajax, you only need jQuery and Bootstrap. On every page add an id to the body tag. Use that id to find a tag that contains the page name (value of a tag).

Example:

page1.html

<body id="page1">
    <ul class="nav navbar-nav">
        <li><a href="page1.html">Page1</a></li>
        <li><a href="page2.html">Page2</a></li>
    </ul>
    <script src="script.js"></script>
</body>

page2.html

<body id="page2">
    <ul class="nav navbar-nav">
        <li><a href="page1.html">Page1</a></li>
        <li><a href="page2.html">Page2</a></li>
    </ul>
    <script src="script.js"></script>
</body>

script.js

<script>
    $(function () {
        $("#page1 a:contains('Page1')").parent().addClass('active');
        $("#page2 a:contains('Page2')").parent().addClass('active');
     });
</script>

Big thanks to Ben! YouTube

Daniel
  • 6,916
  • 2
  • 36
  • 47
Filip Gjorgjevikj
  • 1,367
  • 13
  • 11
1

I had the same problem, and this is what I added in my app launch script, and it worked smoothly. Here is the javascript

$(document).ready(function($){
  var navs = $('nav > ul.nav');

  // Add class .active to current link
  navs.find('a').each(function(){

    var cUrl = String(window.location).split('?')[0];
    if (cUrl.substr(cUrl.length - 1) === '#') {
      cUrl = cUrl.slice(0,-1);
    }

    if ($($(this))[0].href===cUrl) {
      $(this).addClass('active');

      $(this).parents('ul').add(this).each(function(){
        $(this).parent().addClass('open');
      });
    }
  });
});

And the corresponding HTML is shown below. I'm using CoreUI, a phenomenal open source admin template and has support for many front end frameworks like Angular, plain bootstrap, Angular 4 etc.

<div class="sidebar">
<nav class="sidebar-nav open" >
    <ul class="nav" id="navTab" role="tablist">
        <li class="nav-item">
            <a class="nav-link"    href="/summary"><i class="icon-speedometer"></i> Dashboard </a>
        </li>
        <li class="nav-item">
            <a class="nav-link"    href="/balanceSheet"><i class="icon-chart"></i> Balance Sheet </a>
        </li>
        <li class="divider"></li>
        <li class="nav-title border-bottom">
            <p class="h5 mb-0">
                <i class="icon-graph"></i> Assets
            </p>
        </li>
     </ul>
  </nav>
</div>
Krishna Vedula
  • 1,643
  • 1
  • 27
  • 31
1

There is a hitch with the accepted answer in some rare cases for bootstrap 4: In order to use the solution for relative paths like:

<ul class="navbar-nav nav-t">
   <li class="nav-item"><a href="index.php" class="nav-link">Home</a></li>
   <li class="nav-item"><a href="about.php" class="nav-link">About</a></li>
   <li class="nav-item"><a href="blog.php" class="nav-link">Blog</a></li>
   <li class="nav-item"><a href="info.php" class="nav-link">Info</a></li>
</ul>

Then you will find out that the code for:

 if (activePage == currentPage) {
      $(this).parent().addClass('active'); 
    } 

active page returns the whole url and current location returns the current href DOM Element value which is filename.php. To solve this just tweak the code a little by adding a method to correct this:

//... other js/jquery code
var activeMenuItemChanges=function () {
    function stripTrailingSlash(str) {
        if(str.substr(-1)=='/'){
            return str.substr(0, str.length -1);
        }
        return str;
    }
    // for cases where we do not use full url but relative file names in the href of ul>li>a tags:
    function getRelativeFileName(str){
        let page=str.substr(str.lastIndexOf('/')+1);
        if(page.length > 0){
            return page;
        }
        return 'index'|'index.php';
    }

    let url=window.location.pathname;

    let activeLocation=stripTrailingSlash(url);

    let activeFileName=getRelativeFileName(activeLocation);

    $('.nav-item a').each(function() {
        let currentLocation=stripTrailingSlash($(this).attr('href'));
        if(activeFileName==currentLocation){
            $(this).parent().addClass('active');
        }
    });
}
activeMenuItemChanges();

//... other js/jquery code
briancollins081
  • 845
  • 9
  • 19
0

Here is complete Twitter bootstrap example and applied active class based on query string.

Few steps to follow to achieve correct solution:

1) Include latest jquery.js and bootstrap.js javascript file.

2) Include latest bootstrap.css file

3) Include querystring-0.9.0.js for getting query string variable value in js.

4) HTML:

<div class="navbar">
  <div class="navbar-inner">
    <div class="container">
      <ul class="nav">
        <li class="active">
          <a href="#?page=0">
            Home
          </a>
        </li>
        <li>
          <a href="#?page=1">
            Forums
          </a>
        </li>
        <li>
          <a href="#?page=2">
            Blog
          </a>
        </li>
        <li>
          <a href="#?page=3">
            FAQ's
          </a>
        </li>
        <li>
          <a href="#?page=4">
            Item
          </a>
        </li>
        <li>
          <a href="#?page=5">
            Create
          </a>
        </li>
      </ul>
    </div>
  </div>
</div>

JQuery in Script Tag:

$(function() {
    $(".nav li").click(function() {
        $(".nav li").removeClass('active');
        setTimeout(function() {
            var page = $.QueryString("page");
            $(".nav li:eq(" + page + ")").addClass("active");
        }, 300);

    });
});

I have done complete bin, so please click here http://codebins.com/bin/4ldqpaf

gaurang171
  • 9,032
  • 4
  • 28
  • 30
  • Looks interesting, but not keen on the url structure one bit. Thanks though for your effort. Nice but not what I am after, cheers anyway – 422 Jul 18 '12 at 07:21
  • As per your given issue detail, i have done same thing so can you please explain in detail what you want in url structure..? – gaurang171 Jul 18 '12 at 09:48
  • Why would I want to rename the url's to #?page=1 etc – 422 Jul 18 '12 at 10:31
0

None of these worked for me. My Bootstrap setup navigates to separate pages (so I can't do it on a click action, but the active class is removed on the navigation to a new page), and my urls don't match exactly. So here's what I did, based on my exception-based situation. Hope it helps others:

//Adding the active class to Twitter bootstrap navs, with a few alternate approaches

$(document).ready(function() {
  var rawhref = window.location.href; //raw current url 
  var newpage = ((window.location.href.match(/([^\/]*)\/?$/)[1]).substring(1)); //take only the last part of the url, and chop off the first char (substring), since the contains method below is case-sensitive. Don't need to do this if they match exactly.
  if (newpage == 'someNonMatchingURL') {  //deal with an exception literally
    newpage = 'matchingNavbarText'
    }
  if (rawhref.indexOf('somePartofURL') != -1) { //look for a consistent part of the path in the raw url to deal with variable urls, etc.
    newpage = "moreMatchingNavbarText"
    }
  $(".nav li a:contains('" + newpage + "')").parent().addClass('active'); //add the active class. Note that the contains method requires the goofy quote syntax to insert a variable.

});
awvidmer
  • 155
  • 1
  • 14
0

To activate the menus and submenus, even with params in the URL, use the code bellow:

// Highlight the active menu
$(document).ready(function () {
    var action = window.location.pathname.split('/')[1];

    // If there's no action, highlight the first menu item
    if (action == "") {
        $('ul.nav li:first').addClass('active');
    } else {
        // Highlight current menu
        $('ul.nav a[href="/' + action + '"]').parent().addClass('active');

        // Highlight parent menu item
        $('ul.nav a[href="/' + action + '"]').parents('li').addClass('active');
    }
});

This accepts URLs like:

/posts
/posts/1
/posts/1/edit

Seralto
  • 1,016
  • 1
  • 16
  • 30
0
$(function() {
// Highlight the active nav link.
var url = window.location.pathname;
var filename = url.substr(url.lastIndexOf('/') + 1);
$('.navbar a[href$="' + filename + '"]').parent().addClass("active");

});

For more details Click Here!

Shamsur Rahman
  • 283
  • 5
  • 19