Simple Expand/Collapse for the Quick Launch in SharePoint 2013 or SharePoint Online

Yesterday I helped my pal Marcel Meth (@marcelmeth) with a pretty simple little task, but everything’s simple if you know how to do it! We needed to add simple accordion-like expand/collapse functionality to the Quick Launch on the pages in a Site Collection. Because there were going to be a lot of links in the Quick Launch (mostly links to different views of lists), it was getting pretty cumbersome to wade through. By adding this expand/collapse capability, we could improve the user experience (UX). It’s little stuff like this that makes SharePoint usable. Never underestimate the power of a small tweak like this.

This code works on a Team Site on SharePoint Online in Office365 with its Quick Launch exposed in the normal way. Any other customization you have in place may interfere with this working. (Yadda, yadda, disclaimer, YMMV, etc.) I’m sure it will work for you – possibly with some tweaks – in any SharePoint 2013 or SharePoint Online site. You can add this script to a single page or to the master page if you’d like it to work on all pages in the Site Collection.

// Find all the top level links in the Quick Launch that have children
var topLevelLinks = $("div[id$='QuickLaunchMenu'] > ul > li:has('ul') > a");

// Prepend the little "twiddle" icon to each top level link
topLevelLinks.prepend("<span class='ms-commentexpand-iconouter ql-icon'><img alt='expand' src='/Comm/Comms2/_themes/1/spcommon-B35BB0A9.themedpng?ctag=2' class='ms-commentexpand-icon'></span>");

// We're starting with all of the sections collapsed. If you want them expanded, comment this out.
topLevelLinks.closest("li").find("> ul").hide();

// Set up for the click even of on the top level links
topLevelLinks.click(function(e) {

  // We're going to stop the default behavior
  e.preventDefault();

  // Find the elements we need to work with
  var childUl = $(this).closest("li").find("> ul");
  var isVisible = childUl.is(":visible")

  // If the section is visible, hide it, and vice versa
  if(isVisible) {  

    // Replace the icon with its antitheses
    $(this).find(".ql-icon").replaceWith("<span class='ms-commentexpand-iconouter ql-icon'><img alt='Expand' src='/Comm/Comms2/_themes/1/spcommon-B35BB0A9.themedpng?ctag=2' class='ms-commentexpand-icon'></span>");
    // Hide the child links by sliding up. Note: You could change the effect here.
    childUl.slideUp();

  } else {

    // Replace the icon with its antitheses
    $(this).find(".ql-icon").replaceWith("<span class='ms-commentcollapse-iconouter ql-icon'><img alt='Collapse' src='/Comm/Comms2/_themes/1/spcommon-B35BB0A9.themedpng?ctag=2' class='ms-commentcollapse-icon'></span>");
    // Show the child links by sliding down. Note: You could change the effect here.
    childUl.slideDown();

  }

});

20 Comments

  1. Hi Marc,

    Just an aside, this seems to need the Site Collection Publishing feature to be switched on to give you the Navigation menu option rather than the individual quick launch. It would appear the two options have a different layout on the page.

    Paul.

    Reply
  2. For one who does not a single thing about jQuery, do you simple copy and paste this into a script editor on a page or am i missing something?

    Reply
    • Chris:
      I’d suggest creating a file and referencing it in a Content Editor Web Part (CEWP). However, you’ll also have to determine if you need to add a reference to jQuery. It’s possible that it’s already loading in the master page or some other way. Check with whomever manages those aspects of your environment.

      M.

      Reply
  3. Hi Marc,

    Awesome post! Very much enjoying the solution, but had to adjust it a bit for my main stakeholders use case in that the headings needed to be functional links. I attempted to adjust the code as below, and while it works it does not do so very well from a look and feel perspective. Would you suggest I rewrite the entire function, or does it make sense to set up the events in a different way? My jQuery-fu is not so strong yet :)

    $( document ).ready(function() {

    // Find all the top level links in the Quick Launch that have children
    var topLevelLinks = $(“div[id$=’QuickLaunchMenu’] > ul > li:has(‘ul’) > a”);

    // Prepend the little “twiddle” icon to each top level link
    topLevelLinks.prepend(“”);

    // We’re starting with all of the sections collapsed. If you want them expanded, comment this out.
    topLevelLinks.closest(“li”).find(“> ul”).hide();
    topLevelLinks.each(function(){

    var link = $(this).attr(‘href’); // get link from heading
    $(this).children(‘span.additional-background.ms-navedit-flyoutArrow’).attr( “href”, link ); //apply the href attribute to the span containing the name of the navigation item.
    $(this).children(‘span.additional-background.ms-navedit-flyoutArrow’).css( “cursor”, “pointer”); //bad fix to avoid the underline behaviour caused by the alterations (looks like basic hyperlink on mouse over)

    $(this).children(‘span.additional-background.ms-navedit-flyoutArrow’).click(function (f){
    f.stopPropagation();//prevents opening of the accordion if intent to navigate so if you click on the text the event to expand the menu does not fire
    var link2 = $(this).attr(‘href’);
    window.location = link2; // this could probably be done better :)
    });

    $(this).removeAttr(‘href’);

    });

    // Set up for the click even of on the top level links
    topLevelLinks.click(function(e) {

    // We’re going to stop the default behavior
    //e.preventDefault();

    // Find the elements we need to work with
    var childUl = $(this).closest(“li”).find(“> ul”);
    var isVisible = childUl.is(“:visible”)

    // If the section is visible, hide it, and vice versa
    if(isVisible) {

    // Replace the icon with its antitheses
    $(this).find(“.ql-icon”).replaceWith(“”);
    // Hide the child links by sliding up. Note: You could change the effect here.
    childUl.slideUp();

    } else {

    // Replace the icon with its antitheses
    $(this).find(“.ql-icon”).replaceWith(“”);
    // Show the child links by sliding down. Note: You could change the effect here.
    childUl.slideDown();

    }

    });
    });

    Reply
  4. Hi Marc,

    I can’t get the small + and – icons to appear between the > and the Quick Launch menu item.

    Coud you please provide some guidance.

    Henric

    Reply
    • Hi again,

      Never mind, I found that I had the wrong URL to spcommon file. With the right one I got a small triangle pointing to the right and when expanded a filled triangle pointing down-right.

      Thanks for a nice solution to a problem that should have a built in functionality.

      Henric

      Reply
  5. Hi Marc,

    Great post.

    Do you know if it’s possible to have the .menu-item-text be made an anchor for reaching the parent site when clicked, whilst .ms-core-listMenu-item would still activate the accordion when clicked (without loading the parent site)?

    Thanks
    Steve

    Reply
  6. post is great. any one help to modify this script when i click to parent menu until i am inside child menu i want to keep open child menu.. because user when click to next child its collapse. it collapse when user click on other parent any idea

    Reply

Have a thought or opinion?