Creating an accordion-style SharePoint Quick Launch menu with jQuery

About two months ago, a colleague of mine told me of a requirement he had to build an accordion-style menu for an intranet MOSS portal he was building. Not knowing where to start, he asked me what he could do. I advised him that he could either try to work with the <SharePoint:AspMenu> control used by the Quick Launch out of the box or he could use the Accordion control found in the AJAX.NET Control Toolkit and (combined with the SharePoint navigation providers), he could roll his own menu control. They never got around to actually doing this as more critical requirements came about and they eventually postponed this accordion-style menu to a later phase.

Last weekend, I finally decided to look into the examples and documentation around jQuery. I had heard of it before but never really had a chance to play around with it. But I decided that it would be a worthwhile investment of a few hours to learn it, especially since I had read a few weeks ago that Microsoft had put it full jQuery support into Visual Studio 2010. What I found after a few hours of digging in impressed me. I can see why everyone seems to be buying in and using jQuery. It simply makes client-side, rich internet application development much simpler. I have never enjoyed writing Javascript (frankly, I've tried to avoid it as much as possible) but with jQuery, it makes it so easy.

So, being as excited as I was, I started to dream up some ideas I had on how I could use jQuery. I have kicked around a few ideas with some of my colleagues and acquaintances and the ones they thought were good ideas, I will start to build during the upcoming days and months. I will release the code either here (if it is just small snippet code) or in CodePlex if I build out libraries or toolkits. But yesterday, as I was laying in my bed freezing (it was 45 degrees in my house because my furnace went out and had to be repaired this morning), I thought about the accordion control my colleague mentioned. I thought to myself, now this is something I think could do quickly with jQuery. So today, as I waited for the service guy to fix my furnace and for my new treadmill to be delivered, I wrote some jQuery code to make the SharePoint Quick Launch menu work like an accordion. 

Getting Started

By default, the following image is the default appearance of the Quick Launch menu in my dummy test portal: 

I annotated the image in order to better explain what I did. First, in order to understand the javascript I wrote, it is important to understand the html output that is emitted by the Quick Launch menu. Every site in the menu is outputted as a table (item B). That table has the CSS class 'ms-navheader' applied by default (I say by default because you can always override the CSS class assigned in the <SharePoint:AspMenu> control; all references to CSS classes here are in reference to the default CSS classes assigned out of the box). Within this table, a link (item A) is added to the actual site. Each of these anchor tags also have the 'ms-navheader' CSS class applied to it. Lastly, each sub-menu section (item C) is another table with the CSS class 'ms-navSubMenu2' applied.

My accordion would function as follows (the UI requirements, if you will):

  • Only one sub menu at a time should be visible.
  • If you click on a site's navigation bar (item B), the sub menu (item c) should appear and all other sub-menus would disappear.
  • If you click on a site's navigation bar to attempt to expand the sub-menu but the site has no sub-items, nothing should happen (the currently visible sub-menu should still remain).
  • Clicking on the site link (item A) should still continue to take you to the site.
  • By default, when the page is first rendered, the current site the user is on should have its sub-menu expanded out.

The following zip file contains the javascript I wrote to satisfy these UI requirements (the zip also contains both the minified and Visual Studio annotated 1.2.6 version of jQuery): quicklaunch_accordion.zip (58.59 kb)

Some highlights and explanations of the code: 

Finding each sub menu 

//For each Quick Launch navigation sub menu:

    $("table.ms-navSubMenu2").each(function(){

        //Find any navigation items under the sub menu that have been selected.

        var selectedNavItems = $(this).find("a.ms-selectednav");

 

        //Find the corresponding navigation header of the current sub menu being processed

        var menuHeader = $(this).parents("tr:eq(0)").prev("tr").find("table.ms-navheader:eq(0)");           

 

        if ($(menuHeader).hasClass("ms-selectednavheader") || selectedNavItems.length > 0)

        {

            //if the navigation header for this sub menu is selected or if there are any

            //selected navigational items in this submenu, show the submenu.

            $(this).show();

        }

        else

        {

            //otherwise, hide the submenu

            $(this).hide();

        }

    });

When the page is first rendered, the above snippet finds each sub-menu and automatically hides or displays them based on the UI requirements above. A sub-menu item link that is selected will have the 'ms-selectednav' CSS class applied. Similarly, if the user is currently on the welcome page of a site that appears on the Quick Launch, the 'ms-selectednavheader' CSS class will be applied to the corresponding table element in the Quick Launch html.

Handling a site's link (item A) click event

//When a user clicks a navigation header, the user should be taken directly

//to the site link. The javascript event handler to hide/display the submenus

//should not be triggered.

    $("a.ms-navheader").click(function(e){

        e.stopPropagation();

    });

 

Normally, the javascript that is triggered when clicking on the table navigation header (item B) would execute because this anchor tag is within that table. Calling stopPropogation() prevents that click event on the table from firing.

 

Event handler for site menu items

 

//Finally, this adds a click event handler for the navigation header table

    $("table.ms-navheader").click(function(e)

    {           

        var subMenu = $(this).parents("tr:eq(0)").next("tr").find("table.ms-navSubMenu2:eq(0)");

        if (subMenu.length > 0)

        {

            //only if we have a submenu should we hide the other submenus and show the current one.

            $("table.ms-navSubMenu2").hide("slow");

            subMenu.show("slow");

        }

 

    });

The above snippet adds an event handler to handle clicks on the table. And the final output of this code is:

Portal home page (on first load) 

 

Portal home page (News expanded) 




Portal Home Page (Search expanded)

Portal Home Page (Sites expanded)

News Home Page

Sub link Page



Comments (40) -

Zishan
Zishan
1/19/2009 5:16:33 PM #

No heat and your writing an accordian? LOL

Excellent Article.

Leshek
Leshek
1/27/2009 11:09:07 PM #

Hi, can you tell me how to use your js files? Where to copy in my WSS? Should I make some changes in default.master?

bart_tubalinal
bart_tubalinal
1/28/2009 2:44:52 AM #

1. Put the javascript files into a folder under the root of your sharepoint site, e.g. "scripts".
2. Using SharePoint Designer, edit the .master file by adding the following inside the head section:
<script src="/scripts/jquery-1.2.6.min.js" type="text/javascript" language="javascript"></script>
<script src="/scripts/accordion.js" type="text/javascript" language="javascript"></script>

The last js file (jquery-1.2.6-vsdoc.js) is just for intellisense support in Visual Studio. It doesn't need to be deployed to your site.

Kabir
Kabir
1/29/2009 8:09:13 AM #

Clean and simple.
Excellent article!!

bart_tubalinal
bart_tubalinal
1/29/2009 8:35:31 AM #

Thanks! I going to post something in the next week about breadcrumbs. Hopefully that's as well-received as this one.

Florian
Florian
2/2/2009 2:32:11 AM #

Hello Bart!

Nice article! I've been searching for something like this for the last couple of weeks.

I have a question though. What happen if I MANUALLY add new Headings and new Links? In this case, it shouldn't be a parent-child relationship between the content of a Heading and a link. I tried to run your code on this scenario and I only see the Headings. Whatever heading I clicked, no sub-menu appears.

What should be modiffied in the source code?

Thanks and keep up the good work.

bart_tubalinal
bart_tubalinal
2/2/2009 3:09:49 AM #

Hi Florian,

Thanks!

That was actually not a scenario I tested. But it still shouldn't matter. There should be no change whatsoever that needs to be made to the JS. It would have to be changes made to the sitemapprovider and your navigation settings. Remember that the JS works off of what is already rendered down to the page. And the quick launch is dependent on Current Navigation in the Navigation settings. So if it doesn't appear there, it won't appear in the Quick Launch.

With headings, by default (second option selected in the Current Navigation section in the Navigation settings page), when you add a new heading, it simply becomes an item inside of the submenu. It doesn't itself become a new header (like a subweb does). Same thing with links that you manually add. They also just become an item inside of the submenu. If you make the link a child of the heading (in the Navigation settings, making sure it's underneath the heading and indented), that won't appear at all on the Quick Launch (by default). That's not the JS that's causing that. You can try it yourself by removing the reference to the javascript in your master file.

Now if you did want to have the heading show up as an actual heading like how subwebs show up, you can choose the third option under the Current Navigation settings. That would make the heading show up as a header in the Quick Launch but that would make every link directly under that web also become a Quick Launch header. Or you could try one of the other site map providers (or roll your own site map provider) and swap out which provider the quick launch is using to get the effect you need.

- Bart

Jagdish
Jagdish
4/9/2009 1:25:42 AM #

I tried adding these JS files, Quick Launch menu headers are collapsed and Menu items are hidden, but when I clicked on Header its its taking to viewlsts.aspx page. I removed link from Quick Launch header, not if I click on Header, its taking me to same page.

-Jagdish

Loge
Loge
4/25/2009 8:31:56 PM #

Hi Bart,
   Thanks for the very nice article.

Hi Florian,
I had the same problem. I added some menu items with headings and links in quick launch menu. but those were not hidden or shown on clicking. So, instead of Click event of table, add code to the anchor click event. But if you have urls specified in the headers, those wont work.
$("a.ms-navheader").click(function(e){
        var subMenu = $(this).parents("tr:eq(0)").next("tr").find("table.ms-navSubMenu2:eq(0)");
        if (subMenu.length > 0)
        {
            //only if we have a submenu should we hide the other submenus and show the current one.
            $("table.ms-navSubMenu2").hide("slow");
            subMenu.show("slow");
        }
       // e.stopPropagation();
    });

I understand this is very late response. I hope this is what you were looking for.

Loge
Loge
4/25/2009 9:00:07 PM #

Dear Moderator,
Please edit my previous comment with the following
change this line
   But if you have urls specified in the headers, those wont work.
to this line
   In the headings, don't specify any URLs. specify javascript:. This will avoid post back and you will get the expanded menu for the selected item

David
David
5/26/2009 12:35:00 PM #

Great start and I like the perceived animation. How could you add session cookie management, so the last group opened (navheader) would be visible by default on the next page? That's the only thing that keeps this from totally rocking.

Deb
Deb
6/3/2009 2:10:35 AM #

This works great!  As I am just new to jquery/javascript, is there an easy way to take what you have and add the expand/collapse functionality to it?  

Deb
Deb
6/3/2009 2:13:18 AM #

Need to clarify the above comment, I would like to be able to manually expand/collapse the menu instead of an auto expand/collapse.  Can ths be easily done?  Thanks.

bart_tubalinal
bart_tubalinal
6/3/2009 10:06:26 AM #

Deb,

Assuming I'm understanding your question correctly, yes that's very easy to do. Just get rid of everything in the Finding Each Submenu section in the above article.

- Bart

Deb
Deb
6/18/2009 3:33:15 AM #

Thanks Bart!!  Just finished rolling out your accordion navigation across my Sharepoint site and it has been well received! Phase II is providing a manual way to expand the navigation instead of auto expanding.  Example:  a "+" on the sites with subsites to enable the menu to expand and a "-" to collapse.  I will test this on my beta site and see what happens!!  Thanks for your script and response.

bart_tubalinal
bart_tubalinal
6/18/2009 12:15:58 PM #

Hi Deb,

That's great to hear. Thanks for letting me know. What you're trying to do shouldn't be hard to accomplish; if you get stuck somewhere, let me know, I can probably help out a little. I can't promise anything since I'm so busy with work that I often have little time left to do anything else but it doesn't hurt to try. Anyways, good luck!

BXT

santhiswaroop
santhiswaroop
7/15/2009 11:16:01 PM #

hi dude

hw r u

ok i like ur code there is some problem with code can u solve me

ok when i am login as administrator its working nice

but when i am login user like read only permissions the quicklaunch cannot expand and collapse

bart_tubalinal
bart_tubalinal
8/11/2009 3:46:04 AM #

Santhiswaroop,

Most likely that's a permissions issue with the user you're logged in as. Are you sure that user has access to the sub items that are in the menu? If not, those items won't appear as part of their menu. The links are security-trimmed so items (pages, lists, document libraries, subsites, etc) that a user has no access to will not be returned by the navigation provider and therefore won't be part of the Quick Launch menu.

BXT

santhiswaroop naik
santhiswaroop naik
8/12/2009 5:31:38 AM #

hi bart

thanks for your reply

and i am getting stiil problem

the problem i have created usera and given permission fullcontrol but when i login its not working

Robbie
Robbie
8/18/2009 9:42:24 AM #

Hello:

For some reason the allitems.aspx in the _layouts folder doesn't seem to be picking up the script in the master page.  Is that because the inacessible _layouts folder (at least to me as I am not Sharepoint central admin) uses a different master page?

Thanks,
R

Robbie
Robbie
8/19/2009 3:33:22 PM #

Changes I made do not affect documents in the _layouts folder.  Any reason why not?

Thanks,
Rob

Damien
Damien
9/3/2009 4:07:05 AM #

Hi Bart,

That's a really great article ! i'm looking for this type of menu since more than 1 week.
I tried to add the 2 JS files in my masterPage but nothing change.

Does it work on a Share Point publishing Site ?

Thanks

Damien.

Stephen Meier
Stephen Meier
10/20/2009 4:05:12 PM #

I am able to get it to work and it works great in FF and Chrome. It is a little jerky in IE.  Is there a something that I can add to the page to prevent this.  I really want to use it.

Thanks again for the scripts

Andrew
Andrew
11/6/2009 7:10:31 PM #

Hi, That is a great job.
I have a quick question, can I use this solution outside of sharepoint?

kamala
kamala
11/20/2009 12:10:52 PM #

Hi Bart,
Its really great job from you, well i have been trying for this quicklaunch functionality but you acheived it with simple jquery, but my requirement is like providing collapse and expandable effect for four levels.I am able to display subsites upto 4 levels but was  not able to give same effect to subsites.That is subsites are getting displayed under without any effect.Any idea regarding my requirement.Thanks.

Phoenix
Phoenix
11/23/2009 12:39:45 AM #

Hey Bart,
This isnt working !. I am not sure how you guys have succeeded in getting this to work. Loge's code too doesnt work. The last section - click event handler is where I am stuck. Can you suggest how to get this working?

Thanks

lei
lei
11/23/2009 3:36:04 PM #

does anyone know why my selected libraries/lists in the quick launch are NOT highlighted?  in the masterpage i added the
<StaticSelectedStyle CssClass="selectednav" .... to the SharePoint aspmenu and that didn't do anything.  i see if the people and groups if i click on a group, the group gets highlighted, but i just couldn't see why the doc libraries/lists are not....  any help is appreciated.  

Harsha Vardhan
Harsha Vardhan
12/6/2009 10:58:18 PM #

Hi

I have added jquery scripts to master pages. When i tried click the link, It will open all the submenus headings. and aslo its not collapsing.

could you please help where i am going wrong or I need to add extra function to work out the requirement ?

Thanks
Vardhan

Tyus
Tyus
12/10/2009 5:45:11 AM #

Wow very nice, I can't wait to try this out.  Good, good stuff this is really motivating me to learn jquery

Carl
Carl
3/10/2010 7:23:35 AM #

Thanks for this accordion code.  Look forward to having it work.  I don't have access to the /scripts on the site so I was hoping to reference the JQuery code on google like so:  (this works on another Quick Lauch semi-accordion script:

<--Script-->
<script type="text/javascript" src="www.google.com/jsapi"></script>;
<script type="text/javascript">
// Load jQuery
google.load("jquery", "1.2.6");
</script>

When I run your accordion the quick launch nav is not affected in any way.  I am obvisouly new to this so I'd appreciate any advice user's of this have.  When I get this working I am lobbying the site owners to integrate the JQuery into the site.  this is for a prototype.

thanks

Woody
Woody
8/3/2010 9:09:02 PM #

I am going to try this now!

Niels
Niels
8/14/2010 9:17:08 AM #

Hi Bart

I've tried to get it to work, but I can't get the menu items Highlighted. what am I doing wrong? Is it in the css file problem lies, or <SharePoint: AspMenu ... ?

David
David
8/25/2010 11:12:50 AM #

Does this work in SharePoint 2010? If not will you create one that does?

vinod
vinod
8/31/2010 6:50:03 PM #

Hi ,
Nice articel,
Is there any chance Top Navigation as Left Navigation instead of Quick Launch with accordion style and how to make rounded corner to the navigation with css any trick.

please help on this.

thanks
vinod

chakri
chakri
2/15/2011 4:17:47 AM #

Hi ,

I got displayed 3 level by adding <asp:submenustyle CssClass="ms-navSubMenu3" />
and StaticDisplayLevels="3" for Quick launch and followed your's article. Every thing fine but by clicking 2nd level i want display 3rd level(with event click).


Please help me how to write jquery

Mary
Mary
3/21/2012 11:57:20 PM #

Hi,

I have 2 static levels and 1 dynamic fly-out menu.
I am trying to use the code, but I cannot get to the dynamic level. is there smth that is blocking it?

YO
YO
10/30/2012 4:40:57 AM #

Thanks for great article.

However somehow, I can't seem to make it happen in my site.  please help

Here is what I have done after downloading the file.

1.unzip 3 files on local machine
2.opened sharepoint designer pointing root site.
3.opened all file folder
4.created the folder called "scripts"
5.pasted those 3 files on the scripts folder.
6.clicked master page icon
7.copyed v4.master to create v4_w_accordion.master.
8.opened the file and pasted the above mentioned lines right after head section like,
<head runat="server">
<script src="/scripts/jquery-1.2.6.min.js" type="text/javascript" ></script>
    <script src="/scripts/accordion.js" type="text/javascript" ></script>
...
9.and saved, published and approved as normal.
10.went to one of sub-site and changed the master file to "v4_w_accordion".

However, the screen doesn't change and remains as before.

Could you please help me?

napster
napster
11/25/2012 1:11:32 PM #

Hi,

I have successfully done the accordion style however, when I browsed the default page(Thumbnails.aspx) for Images list, the changes didn't take effect. Do you have any idea how to solve this?

Regards

napster
napster
11/25/2012 10:02:49 PM #

Hi,

Thanks. I have done it successfully. The only problem is when I go to Images library (thumbnail view), the expand-collapse menu didn't work. Do you have any idea how to solve this?

Regards

Magali D.B.
Magali D.B.
3/11/2013 1:01:54 AM #

Hi there!

I have used your script and modified it to work in a SharePoint 2013 environment. What I did:
- Edit the code to match the id's and classes from SharePoint 2013
- Pasted the code in a separate .js file
- Made a reference to that .js file from the master page
- Added this to the body of the master page: onload="initQuickLaunch()"

So far, it does hide all the submenu's I have. But what I can't manage to do is to show the submenu of a certain header once that header has been clicked on. It just goes directly to the page that has been linked to that header, but what I am looking for is to toggle the show functionality so that all the subsites inside that submenu are shown.



If you would care to please take a look at this code:

function initQuickLaunch() {
  alert('Start script'); //To test if the script has started
    //For each Quick Launch navigation sub menu:
    $("ul#zz16_RootAspMenu>li.static>ul.static>li.static>a.static").each(function(){
      //Find any navigation items under the sub menu that have been selected.
      var selectedNavItems = $(this).find("a.selected");
      
      //Find the corresponding navigation header of the current sub menu being processed
      var menuHeader = $(this).parents("a:eq(0)").prev("a").find("ul#zz16_RootAspMenu>li.static>a.static:eq(0)");          
        
      if ($(menuHeader).hasClass("selected") || selectedNavItems.length > 0)
      {
            //if the navigation header for this sub menu is selected or if there are any
            //selected navigational items in this submenu, show the submenu.
        $(this).show();
        alert('Show submenu'); //To test if the submenu is shown
      }
      else
      {
        //otherwise, hide the submenu
        $(this).hide();
        alert('Hide submenu'); //To test if the submenu is hidden
      }
    });
        
      //When a user clicks a navigation header, the user should be taken directly
      //to the site link. The javascript event handler to hide/display the submenus
      //should not be triggered.
       $("ul#zz16_RootAspMenu>li.static>a.static").click(function(e){
        e.stopPropagation();
        alert('User clicked on navigation header'); //To test if the click is registered
      });

    //When the user hovers over the navigation header, it would be nice
    //to have an indicator that they can click on the header. Usually,
    //browsers use the hand icon to indicate clickable items.
      $("ul#zz16_RootAspMenu>li.static>a.static").hover(function(e){
          $(this).css("cursor", "hand");
      }, function(e){
          $(this).css("cursor", "default");
      });

      //Finally, this adds a click event handler for the navigation header table
      $("ul#zz16_RootAspMenu>li.static>a.static").click(function(e)
      {        
          var subMenu = $(this).parents("a:eq(0)").next("a").find("ul#zz16_RootAspMenu>li.static>ul.static>li.static>a.static:eq(0)");
          if (subMenu.length > 0)
          {
            //only if we have a submenu should we hide the other submenus and show the current one.
            $("ul#zz16_RootAspMenu>li.static>ul.static>li.static>a.static").hide("slow");
        subMenu.show("slow");
      }
      });
};


Could you please take a look at it? This might be useful for others in the future, hence the reason I'd appreciate it of someone would care to see what might be the problem. ;)

Thanks in advance!

Best regards,

Magali

Pingbacks and trackbacks (4)+

Add comment

biuquote
  • Comment
  • Preview
Loading

About the author

Bart X. Tubalinal is a Solutions Architect with over 10+ years experience in building enterprise applications. He also considers himself to be, pound for pound, one of the best developers there is.

Archives

Comments

Comment RSS