Tabbed Web Parts in SharePoint 2013 / Office 365

THIS SCRIPT HAS BEEN UPDATED WITH BUG FIXES AND ADDITIONAL FEATURES, PLEASE USE THE UPDATED SCRIPT LOCATED AT: http://www.markrackley.net/2015/08/16/sharepoint-tabbed-web-partshillbillytabs-3-0/

I think many would agree with me that one of the best things to ever happen to SharePoint 2007 in terms of an improved user experience was Christophe’s EasyTabs over at Path To SharePoint.  This script turned several web parts that were stacked on top of each other into a much more elegant tabbed view.

And there was much rejoicing.

Christophe updated this script to work for SharePoint 2010 as well. I know countless people who have used it with great success.  However, recently I needed to use EasyTabs for a SharePoint 2013 site and discovered that there was not a 2013 version and the 2010 version did not appear to work. So, what’s a jQuery hack to do but write my own solution? Although not quite as eloquent as Christophe’s solution, it gets the job done. The remainder of this blog walks you through what I did and how you can do it as well.

<update>

Christophe contacted me to me know there’s actually a replacement for the Easy Tabs in SP 2013. For more information see these links:

The free version of the SPELL Nav is a replacement for the Easy Tabs. The paid version adds more features, including an edit menu.

</update>

jQuery UI to the rescue

image

I always try to take advantage of those who came before me, and the jQuery UI tabs do all the heavy lifting of creating tabs for me. Now I just need to write a script to find the Web Parts that I want to put in a tabbed view and move their content into the tabs.

Like I said, not quite as elegant

Unlike Christophe’s solution, my script doesn’t take all the web parts in a web part zone and turn them into a tabbed view. Instead, you specify the titles of the web parts that you want to appear in the tabbed view. This is kind of cool because you can pull web parts from different zones into a tabbed view, but it does require you actually do some typing… sorry…

The Script

Below is the script I used for putting SharePoint 2013 web parts into a jQuery UI tabbed view.

THIS SCRIPT HAS BEEN UPDATED WITH BUG FIXES AND ADDITIONAL FEATURES, PLEASE USE THE UPDATED SCRIPT LOCATED AT: http://www.markrackley.net/2014/11/25/sharepoint-tabbed-web-partshillbillytabs2-0/

<!-- Reference the jQueryUI theme's stylesheet on the Google CDN. Here we're using the "Start" theme --> 
<link  type="text/css" rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/themes/start/jquery-ui.css" /> 
<!-- Reference jQuery on the Google CDN --> 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- Reference jQueryUI on the Google CDN --> 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script> 

<script type="text/javascript">
     jQuery(document).ready(function($) {
         //Put the Web Part Title for all the Web Parts you wish
         //to put into the tabbed view into the array below.
        HillbillyTabs(["Web Part Title 1","Web Part Title 2"]);
    });

    function HillbillyTabs(webPartTitles)
    {
        for(index in webPartTitles)
        {
            var title = webPartTitles[index];
            $("#HillbillyTabs").append('<li><a href="#Tab'+index+'">'+title+'</a></li>').after('<div id="Tab'+index+'"></div>');
            $("span:contains('"+title+"')").each(function(){
                if ($(this).text() == title){
                   var webPart = $(this).hide().closest("span").closest("[id^='MSOZoneCell_WebPart']").contents();
                   $("#Tab" + index).append((webPart));
            }});
        }
        $("#tabsContainer").tabs();
}
</script>
<div id="tabsContainer"><ul id="HillbillyTabs"></ul></div>

The script looks for the Web Parts specified by the Web Part Titles passed into the “HillbillyTabs” function. A jQuery UI tab is created for each Web Part. The title for the tab is the Title of the Web Part. Then the contents of that Web Part are moved into the created tab’s content area. Finally, the title of the Web Part is hidden since the tab contains the Title.  That’s all there is to it.

To use the script

To use the scripts, follow these steps:

  1. Upload the above script to a location you can reference in your site (like possibly the Site Assets Document Library)
  2. Create a Web Part Page.
  3. Add the various Web Parts onto the page that you want to appear in the tabbed view.
  4. Add a Content Editor Web Part to the page.
  5. Edit the above script so that the call to the “HillbillyTabs” function contains the titles of the Web Parts you wish to appear in the tabbed view. For instance. If you had a Web Part with the title “Projects” and another Web Part with the title “Tasks”, the section of script you would change would look like this:
    jQuery(document).ready(function($) {
            HillbillyTabs(["Projects","Tasks"]);
        });

     

  6. Link the above script to the Content Editor Web Part.

Ta and Da.. you should now see your Web Parts in a tabbed view.  Here’s a quick video that shows the above steps in action.

image

Persisting tabs

One thing you will notice is that the active tab is not persisted should the page reload. This may not be a big deal, but I know some people find it annoying.  To get around this issue I updated the above script to the script below to use cookies to make the currently selected tab stay selected should the user do something that causes the page to reload. Just follow the same instructions as above but replace the script with the one below.

<!-- Reference the jQueryUI theme's stylesheet on the Google CDN. Here we're using the "Start" theme --> 
<link  type="text/css" rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/themes/start/jquery-ui.css" /> 
<!-- Reference jQuery on the Google CDN --> 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- Reference jQueryUI on the Google CDN --> 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script> 

<script type="text/javascript">
     jQuery(document).ready(function($) {
         //Put the Web Part Title for all the Web Parts you wish
         //to put into the tabbed view into the array below.
        HillbillyTabs(["Web Part Title 1","Web Part Title 2"]);
        //show persisted tab        
        ShowActiveTab();

    });

    function HillbillyTabs(webPartTitles)
    {
        for(index in webPartTitles)
        {
            var title = webPartTitles[index];
            $("#HillbillyTabs").append('<li><a href="#Tab'+index+'" id="TabHead'+index+'" onclick="SetCookie(this.id);">'+
title+'</a></li>').after('<div id="Tab'+index+'"></div>');
            $("span:contains('"+title+"')").each(function(){
                if ($(this).text() == title){
                   var webPart = $(this).hide().closest("span").closest("[id^='MSOZoneCell_WebPart']").contents();
                   $("#Tab" + index).append((webPart));
            }});
        }
        $("#tabsContainer").tabs();
    }

    function SetCookie(id)
    {
           var date = new Date();
           //make the cookie expire in 5 minutes
           date.setTime(date.getTime()+(300*1000));
           var expires = "; expires="+date.toGMTString();
           document.cookie = "ActiveTab="+id+expires+"; path=/";
    }
    
    function ShowActiveTab()
    {
        var name = "ActiveTab";
        var cookieArray = document.cookie.split(";");
        for (index in cookieArray)
        {
            var keyValuePair = cookieArray[index].split("=");
            var key = keyValuePair[0];
            key  = key.replace(/^\s+|\s+$/g, "");
            if (key == name)
            {
                var value = keyValuePair[1];
                $("#" + value).click();
                return;
            }
        }
    }


</script>
<div id="tabsContainer"><ul id="HillbillyTabs"></ul></div>

 

<UPDATE>

“Breaking Layouts” or Some Web Parts not appearing properly

A few people have indicated that they have a problem with the “layouts breaking” or a web part not being displayed properly for some web parts in a tab, I’ve been able to track this down to scripts executing after jQuery.ready() to do things like place items in calendars. To alleviate this problem I added a delay to the execution of the tabs functionality to give these other scripts time to execute. If you are having a problem with shifting layouts, try using the below script.  The script delays for 800ms, if you find this id not long enough try increasing this value in the “setTimeout” function call below.  I’m not enamored with this solution, and if a better solution comes to mind I’ll be sure to let you know!

<!-- Reference the jQueryUI theme's stylesheet on the Google CDN. Here we're using the "Start" theme --> 
<link  type="text/css" rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/themes/start/jquery-ui.css" /> 
<!-- Reference jQuery on the Google CDN --> 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- Reference jQueryUI on the Google CDN --> 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script> 

<script type="text/javascript">
     jQuery(document).ready(function($) {
        
         //Put the Web Part Title for all the Web Parts you wish
         //to put into the tabbed view into the array below.
        setTimeout(function() {
            HillbillyTabs(["Web Part 1","Web Part 2", "Web Part 3"]);
        }, 800);

    });
    

    function HillbillyTabs(webPartTitles)
    {
        for(index in webPartTitles)
        {
            var title = webPartTitles[index];
            $("#HillbillyTabs").append('<li><a href="#Tab'+index+'" id="TabHead'+index+'" onclick="SetCookie(this.id);">'+
title+'</a></li>').after('<div id="Tab'+index+'"></div>');
            $("span:contains('"+title+"')").each(function(){
                if ($(this).text() == title){
                   var webPart = $(this).hide().closest("span").closest("[id^='MSOZoneCell_WebPart']").contents();
                   $("#Tab" + index).append(webPart);
            }});
        }
        $("#tabsContainer").tabs();

        //show persisted tab        
        ShowActiveTab();

    }

    function SetCookie(id)
    {
           var date = new Date();
           //make the cookie expire in 5 minutes
           date.setTime(date.getTime()+(300*1000));
           var expires = "; expires="+date.toGMTString();
           document.cookie = "ActiveTab="+id+expires+"; path=/";
    }
    
    function ShowActiveTab()
    {
        var name = "ActiveTab";
        var cookieArray = document.cookie.split(";");
        for (index in cookieArray)
        {
            var keyValuePair = cookieArray[index].split("=");
            var key = keyValuePair[0];
            key  = key.replace(/^\s+|\s+$/g, "");
            if (key == name)
            {
                var value = keyValuePair[1];
                $("#" + value).click();
                return;
            }
        }
    }


</script>
<div id="tabsContainer"><ul id="HillbillyTabs"></ul></div>

</UPDATE>

Parting thoughts

I don’t love the way I search for the appropriate Web Part. Unfortunately there is no attribute that only contains the title of the Web Part.  There is a title attribute, but it cannot be depended upon to only contain the Web Part Title (I found this out the hard way when SharePoint decided to create a Web Part Description for me that I could not delete. Thanks SharePoint).

The above solution works in either On Premise SharePoint 2013 or Office 365. It may even work with SharePoint 2010, but I have not bothered to try. Regardless, if someone smarter than me knows how to make the script more performant, I’m all ears… err.. eyes?

Thanks once again for allowing me to waste part of your day!  Cheers!

Families in Germany who are facing divers health problem, such persons can buy drugs from the Web without prescription. With the market flooded with divers web-sites selling sundry medicaments, purchasing medicines from th WEB is no longer a trouble for common man. Certain medications are used to treat infections caused by dental abscesses. Of course it isn’t all. If you’re concerned about erectile soundness problem, you probably know about Xenical and Hoodia. Probably each adult knows about Garcinia. (Read more PhentermineXenical). The symptoms of sexual soundness problems in men turn on impossibility to have an erection sufficient for sexual functioning. Certain medications may add to sex drive difficulties, so its essential to cooperate with your soundness care professional so that the prescription can be tailored to your needs. Preparatory to grab Levitra or other medicament, speak to your pharmacist if you have any allergies. Talk to your health care purveyor for more details. Preparatory to ordering this remedy, tell your doctor if you are allergic to anything.

3 comments

  1. Pingback: SharePoint Tabbed Web Parts–HillbillyTabs2.0 |

  2. Lynn Gravel - Reply

    Your code works great (SP2013) and we thank you for your explanation. Our company is bilingual (QC) and I’m running into a problem. We have PointFire installed. Do you have a suggestions so the JS code will display the content according to the language of the Content Editor?

    • mrackley - Reply

      Hi Lynn, this could be done. I tried to send you an email about it, but apparently the email you entered is not real. 🙂

Leave Comment

Your email address will not be published. Required fields are marked *