Updated

10-5-2016:

  1. Included link to javascript version of bootstrap navigation
  2. Updated the navigation code to detect in active -> Contribution by Olly in comments below.

Introduction

Many of my most recent branding projects have all been responsive. Clients are building sites that they want to work on desktops, tablets, & phones. If you’ve ever tried to deal with this request and SharePoint is your platform then you know what a handful this can be. For all my responsive branding projects I always go to Bootstrap. If you don’t know what that is then this article is not for you. We will not going into the details of implementing Bootstrap or the issues / fixes to do that.  If you’re looking for cookie cutter bootstrap in SharePoint then I recommend that you check out Responsive SharePoint.

This article we will simply focus on the navigation. We will be replicating the standard out of the box (OOTB) SharePoint navigation and formatting it in a way that works with Bootstrap 3.0. I’ll provide you with the code snippet and an explanation of how to implement, and what is happening. It should leave you with the functionality of the Bootstrap’s collapsible navigation.

Our main problems with the SharePoint navigation are:

  • SharePoint out of the box navigation is NOT responsive
  • SharePoint out of the box navigation doesn’t work well with touch enabled devices
    • It has hover actions on the navigation, and hover doesn’t work on touch devices

b

Prerequisites

The following need to be reference in your site.

  • jQuery
  • Bootstrap 3.0
  • On-Prem SharePoint environment w/ access to the Masterpage
    • You can see the references these in my master page

SORRY SharePoint Onliner’s and O365’s – this won’t work b/c you can’t use code blocks in the MasterPage

Check out my other post for a JavaScript version that replaces the navigation – https://github.com/tom-daly/sp2013-bootstrap-nav

 

ref

The Navigation Code

You can view the html markup that Bootstrap requires in order to work properly – http://getbootstrap.com/components/#navbar . The OOTB SharePoint navigation does its own thing so it would never work with Bootstrap. In this approach we’ll use the SharePoint top navigation provider but we’ll create our own navigation markup using asp repeaters. The following code will only work for 2 levels deep, it could be modified to work on X number of levels. You would just have to keep nesting repeaters. I am using ASP repeaters in the master page with no code behind in this approach. If you wanted to you could write a user control and simplify what goes into the master page but for me no C# code means less things that could break. There is one minor issue with this approach – see the Known Issues section.

Download Snippet Here

Take a look at how this renders, much better.

render

And when the screen hits the break point. It collapses and you have the mobile friendly menu. The break point is set in the bootstrap CSS (I believe it is 768px). The menu below is also

resp1

And the drop down

resp2

The Code Explained

You can skip this part if you don’t care what the code snippet actually does. I’ll break it down into parts to help you understand so you can make changes to it.

1) It’s up to you to determine where you are going to put the navigation inside your masterpage

In my particular case below I’ve created my own custom header where I put the navbar. I then turn the visibility off on the PlaceHolderTopNavBar (line 543)

ex

2) Looking at just the very high level bootstrap nav html

boot1

3) The Root Level Repeater

The first level I consider the root level. It contains the root navigation node typically “Home”. Below is the best representation of how the data comes back from the topSiteMap navigation provider. Each color is a level. The children of “Home” are the main level. This is similar to the OOTB, you might have seen the first node that isn’t in the navigation provider but just shows up anyway.

nav123 nav1234

Now for the root level. In this screen shot you can see I render the root node then have a second repeater for its children nodes. The html is fairly simple for the first node and gets more involved for the next level.

zerolevel

4) The First Level Repeater

This level gets a bit more interesting because now we have two different classifications of nav nodes, with children and without children. We have to handle each a slight bit different and I’ll explain. If you have children we need to specify a different class to have a drop down. Next it needs a nested repeater to handle the next level (2nd level). If there are no children we can simply just render the navigation node just as we did with the root level. I use the ChildNodes.Count to determine which to hide or show. You might notice that the

  • li’s line 487 & 507, have some other attributes like data-node-count and data-node-index and are REALLY long.  I’ll explain that in the next section.

level_one

4a) First Level

Let’s examine the first <li> the one with children. They are both the same except for the visible attr. We are going to focus on the following attributes, data-node-count, data-node-index, & class.

data-node-count – is not needed, but this will tell you how many sibling nodes are detected. I used this to help generate the if statements for class.

data-node-index – is not needed, but this will tell you the index of the node in amongst it’s current siblings. I used this to help generate the if statements for class.

a

class – this is basically a fancy edition I added which provides a first-node and last-node class. Again you’ll notice this one has “dropdown” in the class, the other

  • won’t because it doesn’t have children and doesn’t need a drop down.
    • The first node of a set will have the class=“dropdown first-node nav-node”
    • The middle nodes would have the class=”dropdown nav-node”
    • The last node would have the class=”dropdown last-node nav-node”

5) The Second Level Repeater

The second level repeater code gets a little simpler. This is our last level and we don’t consider if the node has children or not. We just render the value of the node and leave it at that. If you wanted to go 3, 4 or 5 levels essentially it’s just copy what we’ve already done but I wouldn’t go more than 2 levels. Bootstrap 3.0 removed  support for multilevel dropdowns, citing usability issues as the cause.  You would be on your own if you decided to go for more levels. There are 3rd party plugins available to assist Bootstrap 3.0 with multi levels.

second_level

Conclusion

That explains how I was able to utilize the SharePoint out of the box top navigation provider and build a new menu with ASP repeaters to behave responsively and work with Bootstrap 3.0. This is a simple enhancement that I’ve been re-using on many on of my On-Prem responsive projects. Unfortunately this doesn’t not work for SharePoint Online or O365 as the Masterpage does not allow code blocks. If you are on O365 then I recommend using a javascript based approach – check out another approach here – https://thomasdaly.net/2015/10/13/bootstrap-navigation-for-office-365-sharepoint-2013-using-jquery-and-rest/

Comments
  • chels
    Posted at 9:32 pm September 25, 2017
    chels
    Reply
    Author

    Could you do something like this in SharePoint Online/365, but within a Content Editor web part instead of modding the .master file?

    And then maybe just change the web part layout to include a header row with this in a CE web part at the very top.

    Possible?

    • Tom Daly
      Posted at 7:21 pm October 5, 2017
      Tom Daly
      Reply
      Author

      Yes and No 🙂 . Do not use this method as described above as it involved restructuring the menu in the master page. I actually don’t recommend doing this anymore because if you deploy this via a wsp and decide later that you want to edit the master page with SharePoint Designer then you will get errors ‘Code Blocks not allowed in the Master Page’ .

      My suggestion to you is this, check out my solution for using bootstrap navigation with only javascript
      https://github.com/tom-daly/sp2013-bootstrap-nav

      you can use the masterpage snippet.html file in a content editor to display the navigation (for testing). If you a tiny bit of javascript or jQuery then you can completely hide/remove the out of the box navigation AND then you can inject this new navigation into the page. I don’t have a full write on doing this but its completely possible.

      You need to attach JavaScript and CSS to your site. So… my last suggestion (if you DO NOT want to edit the masterpage) is to use something like SP-Editor [https://chrome.google.com/webstore/detail/sp-editor/ecblfcmjnbbgaojblcpmjoamegpbodhd] It’s a chrome plugin and very powerful!

      You can directly attach CSS or JS to your web or site via the F-12 tool bar.
      https://www.screencast.com/t/9MoPBqcZ

  • Jason
    Posted at 10:05 pm April 7, 2017
    Jason
    Reply
    Author

    Many apologies for trolling an old post, but I was wondering if you still have the snippet available somewhere? I get a 404 from dropbox when I click on your link.

    • Tom Daly
      Posted at 9:15 pm April 12, 2017
      Tom Daly
      Reply
      Author

      thanks for pointing that out. dropbox pulled public folders. I fixed the link in the article

  • Maryetta Carlsley
    Posted at 7:42 pm March 14, 2017
    Maryetta Carlsley
    Reply
    Author

    Shared! Shared! This is AWESOME stuff man! Thank you!

  • pja
    Posted at 9:11 pm February 23, 2017
    pja
    Reply
    Author

    Hi, this is an interesting solution. A few questions for you:
    1. Is this a secure practice for a public facing site?
    2. You mention a “known issues” section. What is the minor issue?
    3. I tried this on our onprem farm and receive a message: “Code blocks are not allowed in this file”. Is there an easy fix?

    Thanks again

  • Carly
    Posted at 5:11 pm January 23, 2017
    Carly
    Reply
    Author

    Hi Tom,
    I tried placing this code directly into the HTML master page, but as you probably already know, it didn’t work. I received the message that something is requiring the page to be saved as an ASPX page. Should I be placing the code somewhere other than the HTML master page?

    • Tom Daly
      Posted at 3:54 am January 25, 2017
      Tom Daly
      Reply
      Author

      this was performed on in the .master file and not the .html->.master. If you are going to modify the .html that gets auto generated into the .master you need to follow there particular format. Actually just looking at the method here .. it’s not a good idea to use it for the .html->.master. Why, because there are many ASP.net tags throughout the article and those need to be set in a particular format the the .html->.master to work properly.

      I have an easier method here, https://github.com/tom-daly/sp2013-bootstrap-nav You just included the reference to the javascript file and then put a standard ‘div’ and it will inject the code.

      You would add the script something alongs the lines of this format

  • David
    Posted at 3:46 pm October 5, 2016
    David
    Reply
    Author

    I tried this out but designer keeps saying “sharepoint:splinkbutton not permitted”

    I tried both with the nav url property of site and sitecollection.

    Any idea?

    Thanks.

    • Tom Daly
      Posted at 2:50 am October 6, 2016
      Tom Daly
      Reply
      Author

      Not 100% you might be missing a reference that it needs. I typically replace the default snippet for the site logo with the SPLinkButton. You can delete those lines and replace it with the default code snippet which I included below.

  • Olly
    Posted at 8:28 am April 29, 2016
    Olly
    Reply
    Author

    I was working on something similar today and found a way to highlight the active navigation node without javascript.

    Effectively you compare Request.RawUrl with the current link’s URL. If the two match, set class=active.

    [code]class="<%# (Request.RawUrl.ToString().ToLower() == Eval("Url").ToString().ToLower()) ? "active" : "" %>"[/code]

    For the top navigation, where you might want to highlight whether you’re in the current section, I did this, which compares the part of the URL between the first two ‘/’ characters:

    [code]class="<%# (Request.RawUrl.ToString().ToLower().Split(‘/’)[1] == Eval("Url").ToString().ToLower().Split(‘/’)[1]) ? "active" : "" %>"[/code]

    • Thomas Daly
      Posted at 10:27 pm May 18, 2016
      Thomas Daly
      Reply
      Author

      very cool – thanks for replying! i will include an update in the article.

  • Leave a Reply