MTJ Hax

Twitter Bootstrap’s Scrollspy Plugin Needs Better Docs

Posted in Uncategorized by mtjhax on February 11, 2013

I was trying to get Twitter Bootstrap’s Scrollspy plugin working so I can have a nice sidebar-nav menu like theirs that highlights automatically as you scroll the page. I created a JSFiddle here to demonstrate what I am trying to do.

Click here to see the non-working example full-screen

Arrrrrrgh! I thought I followed their instructions to the letter. The tag contains attributes data-spy="scroll" to activate scrollspy and data-target="#my-nav" to indicate which nav I want to highlight to match the scrolled page. After much trial-and-error I removed the data-target attribute and presto:

Click here to see the working example full-screen

This contradicts their documentation, so I poked around Stack Overflow looking for answers and I found many people reporting similar issues and not really getting decent answers. Usually they report that nothing happens with scrollspy or the last entry in the list is highlighted and will not change as you scroll. Some further digging uncovered this issue report on the Bootstrap GitHub page.

As it turns out, the Bootstrap folks are assuming that your nav menu will have a wrapper of some sort, like a div, and that the data-target attribute needs to reference the nav wrapper, not the nav itself:

    <body data-spy="scroll" data-target="#my-nav">
    <!-- WRONG -->
    <div>
      <ul id="my-nav" class="nav nav-list affix">
    <body data-spy="scroll" data-target="#my-nav">
    <!-- CORRECT -->
    <div id="my-nav">
      <ul class="nav nav-list affix">

Click here to see the corrected example full-screen

Apparently, my original example worked when I removed the data-target attribute because it defaults to finding the first nav in the body. The instructions on how to activate scrollspy with JavaScript are very misleading. They suggest:

$('#navbar').scrollspy();

This implies that you should call the scrollspy() method on the nav object, but if you do it, it results in the behavior where the last entry in your nav menu is activated and the menu will not change as you scroll. I thought you needed to target the wrapper, as with the HTML attribute method, but this also does not work. If you use $(document.body).scrollspy() it seems to work, but again this seems to be the code defaulting to use the first nav it finds in the page. Apparently, what I should have done from the start is just read the bootstrap.js source code and figured out what was going on — doing that tomorrow and will post an update.

By the way, the official response to this issue report was “good catch, why don’t you fix the docs and open a pull request” and the issue was closed. When I have time I will see if I can help out and not just complain…

UPDATE: After looking at the code it’s pretty obvious. To initialize ScrollSpy with JavaScript, the scrollspy() method should not be called on the target nav, but on the document body or container being scrolled. The documentation is not entirely clear on how to specify the target, because it assumes a familiarity with some common techniques and conventions. The target nav can be specified as an attribute similar to the way the offset is specified. The lack of explicit documentation is probably another oversight since offset is clearly documented. Example:

// using the not-explicitly-documented 'target' attribute
$('body').scrollspy({ target: '#my-nav' });

Another JSFiddle to prove that it works.

Advertisements

18 Responses

Subscribe to comments with RSS.

  1. David Taiaroa said, on March 16, 2013 at 12:59 pm

    Thanks for this. You’ve explained behaviour that I was seeing, but didn’t know why!

  2. Jonas Olsen (@jonasdo) said, on March 20, 2013 at 1:39 pm

    Thank you so much. You just made my day!! Bootstrap documentation sucks

    • mtjhax said, on March 20, 2013 at 3:35 pm

      Well, “sucks” is a bit harsh. I might say it is just a bit terse. Surprised there aren’t more introductory guides to using bootstrap.js online.

  3. Kieran said, on April 30, 2013 at 10:14 am

    Good man, exactly what I was after. Didn’t want the attributes on the body tag, but the examples they give do not show how to do this properly. Thanks.

  4. Dario said, on May 17, 2013 at 9:40 pm

    Just had this problem and fixed it all up. There is a lot of stuff lacking in the documentation. One other thing they do not talk about is the scroll box resizing because as your scroll it leaves the span. So what they did behind the scenes was give each box a set width.

    Lots of little undocumented tricks!

  5. Christoph Rohrer (@chris_rohrer) said, on June 26, 2013 at 8:57 am

    thanks a lot for sharing this – I found out that my problem was that scrollspy looks for the class “nav”. Reading the source is a good idea^^

  6. Alex Leonard said, on July 29, 2013 at 9:26 am

    Thanks for the clarifications! Much appreciated :)

  7. Mike Boardley said, on August 18, 2013 at 12:12 am

    This helped me out a ton as well! – THANK YOU. :)

  8. Anon said, on August 20, 2013 at 3:06 am

    Additional things I needed: the comments with the # broke my code (use // instead).
    You need the javascript OR data-attribute method, not both.
    I used the javascript method for scrollspy and the data attributes data-spy=”affix”, data-offset-top=””, data-offset-bottom=”” to get the affix working.
    If you’re affix-bottom is flickering, it needs a position:relative on one of its parent divs.
    You need to set the .affix’s top and the .affix-bottom bottom on your own, it is not preset.

    • mtjhax said, on August 21, 2013 at 12:57 am

      Putting Ruby comments in JavaScript and HTML examples… facepalm. Fixed. Thanks for the affix tips!

  9. Hudson said, on August 21, 2013 at 5:38 am

    Hey man, thanks a lot!!
    I was almost giving up haha.

    Hugs from Brazil!

  10. Lowwa said, on August 28, 2013 at 2:45 pm

    You saved my life Sir ! I had a very strange behaviour with my nav, items were twinkling between active and non-active state, when I was using the scroll.

    I first thought it was due to a bad value of the ‘offset’ JavaScript option : it was the only parameter described in the doc !

    Thanksfully I found your article and tried to use the ‘target’ option… Now it works like a charm !

  11. Jen said, on September 27, 2013 at 8:23 pm

    Thank goodness for this post! I was totally confused as to what I was doing wrong! My main problem was that I had the class I was spying on , on the nav element, not the wrapper. Once I moved things it worked. PHEW! thanks!!!

  12. Anthony Broadbent said, on October 1, 2013 at 3:24 pm

    I had exactly the same issue and to fix it all I did was correctly declare my doctype “” and it was fixed. I added your code and it still seemed to only select the bottom item. Then when I fixed my DTD it worked so I then removed your JS code and it still worked. I think the reason why your JSFiddle works is because the DTD is already declared for you.
    Just my contribution.
    Thanks
    Ant

    • mtjhax said, on October 1, 2013 at 4:13 pm

      I didn’t fix my issue with JavaScript. I fixed it by moving id="my-nav" from the ul tag to the wrapper div, so the data-target attribute referenced the correct element. This link is an example of a JSFiddle with no JavaScript that causes the problem, and this one is an example of the problem resolved by using the proper data-target. My JavaScript examples were just to show how the Bootstrap docs were a little misleading and missing an explicit description of the target attribute. However, it is very interesting to know that an incorrect doctype can cause similar problems.

  13. Mizzinc said, on November 11, 2013 at 7:20 am

    Finally, a fantastic write up on this. Thank you!

  14. Ryan said, on January 25, 2014 at 4:23 pm

    This was very helpful for figuring out Bootstrap scrollspy affix issues. I notice you add the class “affix” to the unordered list. I’m pretty sure adding data-spy=”affix” to the direct parent to the UL will apply all three affix classes appropriately. That’s what I’ve concluded. They need a layman who knows Bootstrap inside out to write their docs :) Thanks for this, you made me find my mistake


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: