Tabbed Web Parts in SharePoint 2013 / Office 365
tabso365

Tabbed Web Parts in SharePoint 2013 / Office 365

Posted by on Monday, April 29th, 2013  

 

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.

 

<!-- 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> 

<style type="text/css">
</style>

<script type="text/javascript">
     jQuery(document).ready(function($) {
         $(".s4-wpcell").hide();
         $(".s4-wpcell-plain").hide();
         //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 Title 1","Web Part Title 2"]);
        }, 0);

    });

function HillbillyTabs(webPartTitles)
    {
        for(index in webPartTitles)
        {
            var title = webPartTitles[index];
            $("#HillbillyTabs").append('<li><a href="#Tab'+index+'" id="TabHead'+index+'" onclick="SetActiveTab(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']");
                   if ($(webPart).contents().html() != undefined)
                   {
                           webPart = $(webPart).contents();
                   }
                   $("#Tab" + index).append((webPart));
            }});
        }
        $("#tabsContainer").tabs();
        $(".s4-wpcell").show();
         $(".s4-wpcell-plain").show();

    }
</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.

 

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($) {
        $(".s4-wpcell").hide();
         $(".s4-wpcell-plain").hide();
         //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="SetActiveTab(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']");
                   if ($(webPart).contents().html() != undefined)
                   {
                           webPart = $(webPart).contents();
                   }
                   $("#Tab" + index).append((webPart));
            }});
        }
        $("#tabsContainer").tabs();
        $(".s4-wpcell").show();
         $(".s4-wpcell-plain").show();
    }

    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($) {
          $(".s4-wpcell").hide();
         $(".s4-wpcell-plain").hide();

         //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="SetActiveTab(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']");
                   if ($(webPart).contents().html() != undefined)
                   {
                           webPart = $(webPart).contents();
                   }
                   $("#Tab" + index).append((webPart));
            }});
        }
        $("#tabsContainer").tabs();
        $(".s4-wpcell").show();
         $(".s4-wpcell-plain").show();

   }

    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!

 

Disclaimer
The sample scripts are not supported under any Summit 7 Systems standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Summit 7 Systems further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Summit 7 Systems, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Summit 7 Systems has been advised of the possibility of such damages.

Subscribe to RSS Feed

Sign Up for Newsletter

40

40

comments

    May 05
    2013

    Dennis

    Works great Mark. I especially like the ability to include or omit certain web parts from the tab control–whereas Easy Tabs doesn’t let you!
    One note–this javascript or jquery seems to override the style sheet as it makes the font of any lists or libraries that I pull into the tab control… some big and ugly font. Okay its not ugly, I think its Verdana, and its just a bit too big for a list or lib (compared to the default, compact-looking font used by SP 2013 by default). Any ideas why?

    May 06
    2013

    Mark

    Hey Dennis.. that would be because the jQuery UI stylesheet that is needed for the tabs is loaded after SharePoint’s style libraries, and the last style library loaded wins. Sounds like jQuery UI and SharePoint are both using the same style class somewhere. There are multiple ways around this problem. The quickest and easiest might be to get a local copy of the jQuery UI style sheet and just remove the class from it that SharePoint also uses. Not sure what that is off the top of my head. If you have problems finding it, let me know and I’ll try and do some digging.

      Jul 26
      2013

      Bill Burke

      Dennis, In the jquery-ui.css, comment out .ui-widget and .ui- widget input/select/textarea/button. This worked for me.

    May 09
    2013

    David

    Love the look, but I am getting a “init.js failed to load” error when loading or refreshing the page. After clicking “OK” the page loads and works normally. I may be at the threshhold of my JQuery ability, but I would love to get this to work correctly. Any help would be greatly appreciated.

      May 09
      2013

      Mark.Rackley

      David, what version of SharePoint are you using? Is there any other script on the page? How did you add the script to the page?

    May 17
    2013

    Akhil

    Exactly followed the above steps and its not working out for me 🙁
    I am doing it in SharePoint 2013 without Office365

      May 17
      2013

      Mark.Rackley

      Make sure you are using a Web Part page and not a Wiki page. I’ve tested this solution in 2010, 2013, and O365 so I’m not sure exactly what issues you are having, you have given me no actionable information 🙂

        May 17
        2013

        Akhil

        Hi Mark,

        below are the steps in detail:

        1. Pasted all the above script contents in notepad file and saved the script in my local and named as “HillbillyTabs.js”. Added this script in SP “Site Assets”.
        Parameters updated in Script – HillbillyTabs([“Images”,”Documents”]);
        2. Created a webpart page “TABPAGE” with header,left,middle,right and footer columns.
        3. Added “Images” and “Documents” webparts from “Apps” category in left column.
        4. Added “ContentEditor” webpart in header column. Clicked on “Edit Webpart” and specified the content link as “../SiteAssets/HillbillyTabs.js” and then clicked on “test link” resulted in a File Download – Security Warning Dialog box and asked “Do you want to save this file – HillbillyTabs.js” – Save or Cancel.
        5. Clicked on Cancel and then clicked on Content Editor’s “Apply” and then “ok” button.
        6. Stopped Editing the webpart page.
        7. No tabs created for Images and Documents 🙁

      May 17
      2013

      Mark.Rackley

      It sounds like the jQuery library and jQuery UI library are not getting loaded because you would at least see empty tabs created. These scripts are being referenced externally so if your SharePoint 2013 farm does not allow access to those libraries you will have to bring in local copies of those libraries and change the reference in the script. A very quick way to test this is to put the following line in the HillbilyTabs.js script right before the HillbillyTabs([“Images”,”Documents”]); line and after the .ready line

      alert(“jQuery is working”);

      if you don’t get the alert it means the jQuery libraries are not getting loaded.

    May 17
    2013

    David

    Sorry I have been out for a few days. I found that there was something in the Page Viewer web parts that I was trying to “tabify” that was causing the “init.js failed to load” error. After rebuilding the page, the error did not reappear, but now my top bar navigation disappears after the page loads. When I remove the jQueary content editor and the tabs are gone, it reappears. I am using the “Persisting Tabs” version. I will try the original version and see if I get a different result.

    May 23
    2013

    manikanta

    Hi Mark,it works for me ,but here my task is how could we set each tab to a different colour,i need the first tab is yello colour and second one is red like this……how can we set the colours for each tabs,,,,,,Please give me a suggestion on this……

    Jun 03
    2013

    Larry

    Not working for me in Office 365. I get the Tabs to display but the web parts are all in on e long row and clicking the tab doesn’t do anything.

      Jun 03
      2013

      Mark.Rackley

      Larry, it SOUNDS like you may be using a Wiki Page instead of a Web Part page. If you are indeed using a Web Part page can you give me more details so that I may try to reproduce the problem? I have not had any issues in Office 365.

    Jun 03
    2013

    Larry

    Hi Mark,

    I am using the default dispform.aspx on our vendor list. So I open up the list, edit the dispform.aspx and add your code into the page. I believe the DispForm.aspx is default. Let me try to create a standard aspx page and set it as the default for viewing.

      Jun 03
      2013

      Mark.Rackley

      The default forms in SharePoint hide the Web Part’s Title. The Web Part title must be visible or the script can’t find the web part to place it in the tab.
      You need to open up the properties for each Web Part on the form that you want to be in tabs, and set each Web Part’s Chrome Type to “Title Only”. This will cause the title to appear properly and the tabs to work.

    Jun 03
    2013

    Larry

    Yes that did it. Setting the web part to show Title Only made it work just fine.
    Thanks for the help! I have been using easy tabs, but since they upgraded us to Office 2013 I haven’t been able to get it to work. This is perfect. Thanks Again

    Jun 27
    2013

    Paul

    So when I added this my tabs came out great named SHARED DOCUMENTS and PICTURES. But…… in my quick launch the links to those same web parts disappeared. :-/

      Jul 10
      2013

      Mark.Rackley

      Hey Paul, the quick fix would be to rename those quick launch links to something slightly different. In the meantime I’ll poke around the script to alleviate that.

        Jul 26
        2013

        Bill Burke

        Mark, I have the same issue as Paul. Were you able to see anything that may cause/fix this? Thanks -bill

          Jul 26
          2013

          Mark.Rackley

          Hey Bill, I was able to figure this out, just wanted to do more testing before I updated the blog. If you update the following portion of the script this should take care of that issue:

          Change this:
          $(“span:contains(‘”+title+”‘)”).each(function(){
          if ($(this).text() == title){
          var webPart = $(this).hide().closest(“span”).closest(“[id^=’MSOZoneCell_WebPart’]”);
          $(“#Tab” + index).append((webPart));
          }});
          to this:

          $(“span:contains(‘”+title+”‘)”).each(function(){
          if ($(this).text() == title && this.id.indexOf(“WebPartTitle”) != -1){
          var webPart = $(this).hide().closest(“span”).closest(“[id^=’MSOZoneCell_WebPart’]”);
          $(“#Tab” + index).append((webPart));
          }
          });

            Jul 26
            2013

            Bill Burke

            Thanks Mark, Works great…. Thanks for all your efforts. -bill

    Jul 10
    2013

    Mary Kay

    First, I really appreciate you putting the time into this and sharing it! I have implemented this on a web part page (not a wiki page, I promise), and as long as the page is in edit mode, I can see the tabs, and the web parts are displayed perfectly, and all is well with the world. When I stop editing, the whole shebang disappears — the content disappears, and it’s just a white space with the top bar and left navigation. Any ideas?

      Jul 10
      2013

      Mark.Rackley

      Hey Mary Kay, sorry you are having problems. What version of SharePoint and what browser are you using? I’ve heard of this before but have never been able to reproduce it. If there is anyway to give me access to the site so I can see it happen and look at the DOM that would help immensely in solving the problem. Thanks!

    Jul 26
    2013

    Bill Burke

    Interesting behavior on SPS 2013 EE. If in the web part (a document library), I select “Enable Asynchronous Update”, my grouped items show the right count in each group but when expanded will show all documents in the library under each grouping.

    When I uncheck the Asynchronous update, everything shows as it should. (only when in the tabs)

    Not a show stopper, but because I noticed, I thought I would share.

    Jul 26
    2013

    Bill Burke

    HWen my page loads, the web parts on the page (6) load and are in view (stacked), followed by the loading of the tabs. Is there any way to control this?

    This was also an issue with me for Easy Tabs 2007.

    thanks again -bill

      Jul 26
      2013

      Mark.Rackley

      Give this a shot bill. At the top of your script (outside of the tag) add this:

      .s4-wpcell-plain
      { display:none;}
      .s4-wpcell
      { display:none;}

      then add these two lines of script right after “$(“#tabsContainer”).tabs();”

      $(“.s4-wpcell”).show();
      $(“.s4-wpcell-plain”).show();

      Thanks for the feedback and good luck!

        Jul 26
        2013

        Bill Burke

        This works, thanks… I had some issues along the way. With some help from one of the programmers here, this is what happened.

        First put tags around the css (embarassing).

        .s4-wpcell-plain
        { display:none;}
        .s4-wpcell
        { display:none;}

        Next, after running the script, the width of the tabs container went from 100% to adjusting to the content/zone of each web part.

        I prefer having one consistent size.

        So we added a line to your script

        $(“.s4-wpcell”).show();
        $(“.s4-wpcell-plain”).show();
        $(“.s4-wpcell”).width(($(“.ms-webpart-zone”).width()-45)+”px”);

        It is not fluid (responsive) but does nicely with different resolutions.

        Thanks again -bill

          Jul 26
          2013

          Bill Burke

          wordpress stripped out tags…. put style tags around the css……

        Oct 26
        2013

        sri ranga

        hi mark thanks for the good its working good in IE 9 but it is not working in IE8 can you please suggest me on this

          Nov 12
          2013

          Mark.Rackley

          Sorry you are having issues in IE8, I’ve not invested the time to make this compatible with all legacy browsers. For any enhancements like that I’d be happy to discuss putting together a small consulting agreement, otherwise I just can’t justify the time right now. Good luck!

    Sep 04
    2013

    ashbedwell

    I absolutely LOVE this solution. It saves so much space and looks wonderful and clean. It was easy to implement too with a little guidance from my developer friend (I have no programming background so I can’t read between any lines haha). I just wanted to give you kudos for this and thank you so much for sharing!

    Sep 08
    2013

    Mark Marriott

    OK – so I created a brand new Web Part Page (header, left column, body) and set up a couple of web parts in the left column zone. I get exactly the same problem as I described for when I was trying this on a wiki page. I removed all other scripts but to no avail. I changed the couple of web part titles that were using ampersands to use “and” instead, thinking maybe they weren’t being handled, then I edited the script to use my web part titles [“Administration”, “Courses and Participants”, “Participation and Attendance”] but the same problem occurs:
    Administration web part (which is itself a CEWP with a bunch of text and some input buttons to launch various different list newifs forms) disappears and the other two web parts move up the zone. I am struggling to understand this.

    BTW – this is SharePoint 2013 EE.

    it seems that whichever Web Part I put first in the list of titles is the one which disappears.

    Also – I note that when I open SharePoint Designer to remove the hidden web part containing the script link to restore my page to previous state, SPD says the page is a wiki page, but I DEFINATELY created it as a Web Part page.

    Any clues?

      Sep 08
      2013

      Mark.Rackley

      Sorry you are having issues Mark. Is it possible that jQuery is already being loaded? If so, referencing it again can causes strange issues.
      Also, you do not need to encode an & if your web part title has one in it. Go back to my blog, grab the script again as I made a slight change fairly recently.
      Try again on a brand new web part page. Put just ONE List web part on there and the CEWP that links to the script. If that still doesn’t work, here are possible reasons why:

      1) Your script is not getting loaded properly
      2) jQuery is already loaded, try removing the reference
      3) jQuery UI is already loaded, try removing that reference

      The script actually “works” on Wiki pages as well, I just have not done enough testing to say that there are any quirks with a Wiki page which will cause it not to work.

    Oct 24
    2013

    Kyle

    Hi, for some reason when I link the text file to the content editor web part, it sets the web parts I want tabbed into a “bulleted link list” and deletes all other content on the page. (All other content was migrated from SP2010 content databases, but this should be mutually exclusive to styling)

      Nov 12
      2013

      Mark.Rackley

      if you are seeing the bulleted list and the script is not throwing any errors it most likely means that the jQueryUI library is not referenced correctly.

    Apr 10
    2014

    Gerard Fdez

    Thanks Mark! It worked like a charm.