The content of wiki pages can get really long sometimes. My client has asked me to create a table of contents like the one that is used in Word documents to navigate to contents. This article online was quite helpful to get me started. In the article, the author added scripts to the wiki page layout. In my case, my client didn’t use publishing pages. So I added the scripts to web parts and then add the web parts to the content.

Note: This method is based on the use of H1, H2, H3, H4 tags. It wouldn’t work if there is no tags to the content.

Here are the steps:

1. Create a text file using Notepad, name it table_of_contents.txt. Copy the following code to the file

<!-- Table of Contents --> 
<div id="wiki-index"> 
<div class="toc">Table of Contents</div> 
</div> 
<!-- Table of Contents -->
<script type="text/javascript"> 
$(document).ready(function(){ 
$(".ms-bodyareacell H1.ms-rteElement-H1, 
H2.ms-rteElement-H2, H3.ms-rteElement-H3, 
H4.ms-rteElement-H4").each(function(i){   
var current = $(this);   
current.attr("id", "title" + i);   
$("#wiki-index").append(("<a id='link" + i + "' href='#title" +         
i + "' title='" + current.attr("class") + "'>" +         
current.html() + "</a>"));         
}) }); 
</script>
<style> 
#wiki-index{border: 1px black dashed; 
background-color: whitesmoke; float: left; 
padding: 10px; padding-top: 0px; } 
#wiki-index .toc{font-size: 1.1em; 
font-weight: bold; text-align: center; 
padding: 5px; }
#wiki-index a[title=ms-rteElement-H1] 
{ font-size:14px; font-weight: bold} 
#wiki-index a[title=ms-rteElement-H2] 
{ font-size:12px; font-weight: normal} 
#wiki-index a[title=ms-rteElement-H2] div 
{ margin-left: 10px;} /*Add indent in front*/
#wiki-index a[title=ms-rteElement-H3] 
{ font-size:10px;} 
#wiki-index a[title=ms-rteElement-H3] div 
{ margin-left: 15px;} /*Add indent in front*/
#wiki-index a[title=ms-rteElement-H4] 
{ font-size:8px;} 
#wiki-index a[title=ms-rteElement-H4] div 
{ margin-left: 20px;} /*Add indent in front*/
</style>

The above code contains html, jQuery and CSS. The jQuery scripts append links of H1, H2, H3 and H4 text to the end of the Table of Contens.

2. Open the site collection in SharePoint Designer 2010. Import the text file to Site Assets or Style Library folder.

3. Right click on the text file, select “Properties”. Copy the location URL.

4. Go back to the browser. Edit the page and insert a Content Editor Web Part to the content area.

5. Edit the Content Editor Web Part and enter the URL copied in step 3 to the content link text box. Test the link, make sure it works.

6. Save the page. That’s it. You can export the above contnet editor web part and upload it to the web part gallery for reuse on other pages.

Tips:

When user jumps to the very bottom of a wiki page, it may take a while to scroll back up. A back to top button might be useful in this case. Here’s how to add one. Note: The following steps need to work with the table of contents.

1. Create another text file using Notepad, name it top_button.txt. Copy the following code to the file

<div class="top_button">
<a href="#wiki-index">Back to Top</a>
</div>
<style>
/*Display the button to the right of the content*/ 
.top_button {  float:right; }
</style>

2. Open the site collection in SharePoint Designer 2010. Import the text file to Site Assets or Style Library folder or wherever you stored the table_of_contents.txt file above.

3. Follow step 3-6 in the first part of this article. Note: Need to move the web part to the bottom of a section or the page. You can have as many of this web part as needed.

Reference:

http://www.n8d.at/blog/enhance-wiki-page-layout-by-adding-a-navgational-table-of-contents/

http://www.jankoatwarpspeed.com/automatically-generate-table-of-contents-using-jquery/

35 thoughts on “Add Table of Contents to a Wiki page in SharePoint 2010

  1. Thanks for the post. I’ve followed the steps above however the only thing that display on my wiki page is the gray box that states “Table of Contents”. I’ve created several heading H2,H3&H4 as samples but they do not appear in the TOC, any suggestions? My enviroment is 2010. THX.

    1. Hi Nick,

      Have you tried using F12 to see if the javascripts are working properly? Also make sure the classes specified in the javascript matches the ones used in your content.

      Let me know how you getting on with it. Maybe post your HTML content here if you can.

      Cheers
      June

  2. Thanks for the article, however i can’t get it to work. I added a web part and the grey box of table of contents is showing up, but it is not showing any of my items in the TOC box. can you help me? the error i get when i press f12 is: SCRIPT5007: The value of the property ‘$’ is null or undefined, not a Function object. i look at that line and it says: $(document).ready(function(){
    i am wondering, do i need to put on this page somewhere, where my jquery folder is on my web server? if so, where do i do this at?
    thanks.

  3. Hello. Just like Nick, I get the dotted box with the words ‘Table of Contents’ but nothing else builds. You mentioned that the code uses JQuery, so I added a script reference to it too, but still no TOC builds. The SP2010 wiki page uses all the standard Hx tags.

  4. Hello June and Nick.

    I found some faults in the JS and have fixed it. I changed a few things to make it a little easier for others to read and understand. I dropped the H1 formatting, as I agree with STFBauer that the first H1 should be the title, and it shouldn’t be part of the TOC.

    Here is my version that works fine on SP2010 wiki pages;

    Table of Contents

    $(document).ready(function(){
    $(“.ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4”).each(function(i){
    $(this).attr(“id”, “title” + i);
    $(“#wiki-index”).append(“” + $(this).text() + ““);
    })
    });

    #wiki-index {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wiki-index .toc{font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wiki-index a[title=ms-rteElement-H2] {font-size:12px; font-weight: normal;}
    #wiki-index a[title=ms-rteElement-H3] {font-size:11px; font-weight: normal; margin-left: 5px;}
    #wiki-index a[title=ms-rteElement-H4] {font-size:10px; font-weight: normal; margin-left: 10px;}

  5. @@

    $(document).ready(function(){
    $(“.ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4”).each(function(i){
    $(this).attr(“id”, “title” + i);
    $(“#wiki-index”).append(“” + $(this).text() + ““);
    })
    });
    @@

  6. June. send me an email and I’ll post back the revised code for you to put into a text block, as I don’t know how to bypass the text pre-processing on your site from converting the HTML / JS back to plain text.

  7. <script type="text/javascript"> 
    $(document).ready(function(){
    	$(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
    		$(this).attr("id", "title" + i);
    		$("#wiki-index").append("<a href='#title" + i + "' title='" + $(this).attr("class") + "'>" + $(this).text() + "</a><br />");
    	})
    });
    </script>
    
    <style> 
    #wiki-index {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;} 
    #wiki-index .toc{font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wiki-index a[title=ms-rteElement-H2] {font-size:12px; font-weight: normal;} 
    #wiki-index a[title=ms-rteElement-H3] {font-size:11px; font-weight: normal; margin-left: 5px;} 
    #wiki-index a[title=ms-rteElement-H4] {font-size:10px; font-weight: normal; margin-left: 10px;} 
    </style>
    
  8. Hello June and Nick.

    I found some faults in the JS and have fixed it. I changed a few things to make it a little easier for others to read and understand. I dropped the H1 formatting, as I agree with STFBauer that the first H1 should be the title, and it shouldn’t be part of the TOC.

    Here is my version that works fine on SP2010 wiki pages (please remove my prior posts):

    <!-- Table of Contents --> 
    <div id="wiki-index"> 
    <div class="toc">Table of Contents</div> 
    </div> 
    <!-- Table of Contents -->
    
    <script type="text/javascript"> 
    $(document).ready(function(){
    	$(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
    		$(this).attr("id", "title" + i);
    		$("#wiki-index").append("<a href='#title" + i + "' title='" + $(this).attr("class") + "'>" + $(this).text() + "</a><br />");
    	})
    });
    </script>
    
    <style> 
    #wiki-index {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;} 
    #wiki-index .toc{font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wiki-index a[title=ms-rteElement-H2] {font-size:12px; font-weight: normal;} 
    #wiki-index a[title=ms-rteElement-H3] {font-size:11px; font-weight: normal; margin-left: 5px;} 
    #wiki-index a[title=ms-rteElement-H4] {font-size:10px; font-weight: normal; margin-left: 10px;} 
    </style>
    
  9. Hello June.

    Here is an even more improved version of your wiki TOC. This one now has a button to show / hide the TOC plus it appends sequential numbers to each header row.

    function hideTOC() {
    document.getElementById("theTOC").style.display = 'none';
    document.getElementById("show").style.display = 'block';
    document.getElementById("hide").style.display = 'none';
    }

    function showTOC() {
    document.getElementById("theTOC").style.display = 'block';
    document.getElementById("show").style.display = 'none';
    document.getElementById("hide").style.display = 'block';
    }

    Table of Contents

    [hide]
    [show]

    $(document).ready(function(){
    var L2=0, L3=0, L4=0;
    $(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
    theLevel=$(this).attr("class").substr(14,2);
    if (theLevel=="H2") {
    L2=L2+1;
    L3=0;
    L4=0;
    theLevelString=""+L2;
    }
    else if (theLevel=="H3") {
    L3=L3+1;
    L4=0;
    theLevelString=""+L2+"."+L3;
    }
    else {
    L4=L4+1;
    theLevelString=""+L2+"."+L3+"."+L4;
    }
    $(this).attr("id", "heading_" + i);
    $("#theTOC").append("" + theLevelString + " " + $(this).text() + "");
    });
    });
    showTOC();

    #wikiTOC {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wikiTOC .TOCheader {font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wikiTOC .closehide {font-size: 11px; font-weight: normal;}
    #wikiTOC a[title=H2] {font-size:12px; font-weight: normal;}
    #wikiTOC a[title=H3] {font-size:11px; font-weight: normal; margin-left: 8px;}
    #wikiTOC a[title=H4] {font-size:10px; font-weight: normal; margin-left: 16px;}

  10. Hello June

    Here is another version of your wiki TOC with more improvements. This version now has a button to show / hide the TOC plus it appends sequential numbers to each heading. Makes the whole thing look and behave just like a media wiki TOC.

    <script type="text/javascript" src="/site_name/path_to_jquery.js"></script>
    <script type="text/javascript">
    function hideTOC() {
    	document.getElementById("theTOC").style.display = 'none';
    	document.getElementById("show").style.display = 'block';
    	document.getElementById("hide").style.display = 'none';
    }
    </script>
    <script type="text/javascript">
    function showTOC() {
    	document.getElementById("theTOC").style.display = 'block';
    	document.getElementById("show").style.display = 'none';
    	document.getElementById("hide").style.display = 'block';
    }
    </script>
    
    <div id="wikiTOC">
    <table style="padding: 5px;"><tr>
    	<td><div class="TOCheader">Table of Contents</div></td>
    	<td>
    		<div class="closehide" id='hide'>[<a href='#' title='Click to hide' onClick="hideTOC()">hide</a>]</div>
    		<div class="closehide" id='show'>[<a href='#' title='Click to show' onClick="showTOC()">show</a>]</div>
    	</td>
    </tr></table>
    <div id='theTOC'>
    <script type="text/javascript"> 
    $(document).ready(function(){
    	var L2=0, L3=0, L4=0;
    	$(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
    		theLevel=$(this).attr("class").substr(14,2);
    		if (theLevel=="H2") {
    			L2=L2+1;
    			L3=0;
    			L4=0;
    			theLevelString=""+L2;
    			}
    		else if (theLevel=="H3") {
    			L3=L3+1;
    			L4=0;
    			theLevelString=""+L2+"."+L3;
    			}
    		else {
    			L4=L4+1;
    			theLevelString=""+L2+"."+L3+"."+L4;
    			}
    		$(this).attr("id", "heading_" + i);
    		$("#theTOC").append("<a href='#heading_" + i + "' title='" + theLevel + "'>" + theLevelString + " " + $(this).text() + "</a><br />");
    	});
    });
    showTOC();
    </script>
    </div>
    </div>
    
    <style> 
    #wikiTOC {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wikiTOC .TOCheader {font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wikiTOC .closehide {font-size: 11px; font-weight: normal;}
    #wikiTOC a[title=H2] {font-size:12px; font-weight: normal;}
    #wikiTOC a[title=H3] {font-size:11px; font-weight: normal; margin-left: 8px;}
    #wikiTOC a[title=H4] {font-size:10px; font-weight: normal; margin-left: 16px;}
    </style>
    
  11. well it works to display a TOC. but the links in the TOC don’t work as they are anchors to the name of the elements like “#heading_0”. The actual H1, H2, H3 links etc do not have named anchors too, so I can’t see how the hyperlinks in the TOC will work. Anyone got the links to actually function in this TOC?

    1. Hello Jason. The hyperlinks work by linking to the parts of the page with the same ‘H’ number. The number is applied sequentially as jquery parses the page. Essentially, jquery replaces the native SharePoint heading tags with a sequential list of numbers.
      I’ll post a new version of the code to the site soon….. as soon as I work out the magical wordpress tag to use to make code show correctly

  12. One big annoyance in the postings above is that a simple copy-n-paste doesn’t work because the TABs are converted by SPACEs! If you replace the space back to TAB (fe. in the posts from sunnyape) it works fine. However, it’s NOT doable in the latest posts from sunnyape because it’s too much manual labor. Request is to upload the latest version in this blog, so that everybody can download. It’s really worth the effort because these scripts are *very* handy indeed, thx in advance.

  13. Hello to all the visitors looking for a SharePoint wiki Table of Contents. Here is my latest version. Have tested on SP2010, using most modern browsers and JQuery v1.42

    <!-- SharePoint WIKI Table of Contents. Sunnyape, August 2013 -->
    
    <script type="text/javascript" src="/<PATH_TO_JQUERY.js"></script>
    
    <script type="text/javascript">
    function hideTOC() {
     document.getElementById("theTOC").style.display = 'none';
     document.getElementById("show").style.display = 'block';
     document.getElementById("hide").style.display = 'none';
    }
    </script>
    <script type="text/javascript">
    function showTOC() {
     document.getElementById("theTOC").style.display = 'block';
     document.getElementById("show").style.display = 'none';
     document.getElementById("hide").style.display = 'block';
    }
    </script>
    
    <div id="wikiTOC">
    <table style="padding: 5px;"><tr>
     <td><div class="TOCheader">Table of Contents</div></td>
     <td>
      <div class="closehide" id='hide'>[<a href='#' title='Click to hide' onClick="hideTOC()">hide</a>]</div>
      <div class="closehide" id='show'>[<a href='#' title='Click to show' onClick="showTOC()">show</a>]</div>
     </td>
    </tr></table>
    <div id='theTOC'>
    <script type="text/javascript"> 
    $(document).ready(function(){
     var L2=0, L3=0, L4=0;
     $(".ms-bodyareacell h2, .ms-bodyareacell h3, .ms-bodyareacell h4").each(function(i){
      theLevel=$(this).attr("class").substr(14,2);
      if (theLevel=="H2") {
       L2=L2+1;
       L3=0;
       L4=0;
       theLevelString=""+L2;
       }
      else if (theLevel=="H3") {
       L3=L3+1;
       L4=0;
       theLevelString=""+L2+"."+L3;
       }
      else {
       L4=L4+1;
       theLevelString=""+L2+"."+L3+"."+L4;
       }
      $(this).attr("id", "heading_" + i);
      $("#theTOC").append("<a href='#heading_" + i + "' title='" + theLevel + "'>" + theLevelString + " " + $(this).text() + "</a><br />");
     });
    });
    hideTOC();
    </script>
    </div>
    </div>
    
    <style> 
    #wikiTOC {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
    #wikiTOC .TOCheader {font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
    #wikiTOC .closehide {font-size: 11px; font-weight: normal;}
    #wikiTOC a[title=H2] {font-size:12px; font-weight: normal;}
    #wikiTOC a[title=H3] {font-size:11px; font-weight: normal; margin-left: 8px;}
    #wikiTOC a[title=H4] {font-size:10px; font-weight: normal; margin-left: 16px;}
    </style>
    
    1. Thank you very much sunnyape that’s really awesome.
      I had to adapt it a little for Sharepoint 2013 online but it works very nice.

      1. Hello mbraun. Can you post what are the changes made ​​in the sunnyape’s script for sharepoint 2013? Very thanks.

        Thank you all for sharing the knowledge.

    2. Hi,

      I am facing one issue with this script. Once i click the TOC element, i was directing to appropriate section in the same page, where as when i click browser back button its not taking me to TOC part.
      Can any one help to to resolve this issue.

      ~Siva

      1. Hello Siva.

        The back button on your browser can’t provide that sort of activity; it just takes you back to the prior site page.

        If you want to scroll back up the page to where the TOC is, you’d need to add something to the Wiki page like a floating ‘Back to TOC’ or ‘Top of Page’ button. There are numerous articles on the web on how achieve this.

      2. Hello Sunnyape,

        Thanks for your response, i would like to conduct the following actions on my TOC.
        1. Click on Level 1 Heading.
        2. Go back to your TOC and Click on another L1 Heading.

        Now, if i click my broswer button, i would expect to goto my TOC (hope this is how Wiki behaves) my url changes from L1 heading to WikiTOC heading, but page content is not moving to TOC.

        Do i need to add any other scripting to your TOC script? Please do let me know your expert thought on this?

        ~Siva

      3. Siva. You seem to be confused as to what the purpose of the ‘back’ button on your browser is for. As I said, if you want to ‘go back to the TOC’ you have to either:
        1) Move the browser’s side scroll bar to make the page scroll back up.
        2) Add some code to make the page scroll back up to the TOC.

        Try Googling “page scroll up button” or “jump to top of page” for a thousand articles on how to do it.

  14. I’m trying to add this to SharePoint 2013. The banner shows up but the content does not…

    I added your text above to a TXT file, which I then included as part of a Content Editor Web Part.

    As is well except for listing out the TOC sections. Any recommendations?

    1. Hello Marc

      I’ve not tested with SP2013 yet, so the CSS tags used for each .ms-bodyareacell part on the page may need to be changed.

      Wait for MBraun’s response above. If that doesn’t work, I’ll do a test with SP2013 to see what needs to be changed.

    2. Marc. Just a question. You did alter the code to provide the path to where you have JQuery on your SharePoint site, right? If JQuery is not there and referenced, the ‘banner’ will appear and be empty, just as you described.

      PS. there is a typo in my code example. Make sure you don’t put in the excess left bracket ‘<' before the path:

      1. Great code here, sunnyape. I’m using now in SP2013. The only change I had to make, aside from adding my JQuery path to the “PATH TO JQUERY” spot at the top, was removing the “.ms-bodyareacell” part of the loop for each header (2, 3, and 4).

        One question: any way to “Show” the TOC by default? Also, any way to exclude the web part title? I can probably work out on my own, but you’re miles ahead of me in terms of JS development, so I thought I’d ask.

        Thanks again!

        –Ryan

      2. Ryan

        Yes, you can make the TOC to make it display in the open state. At the end of the JS script that builds the TOC, change ‘hideTOC();’ to ‘showTOC();’

        As for making the Content Editor webpart show no title, that is done by altering its settings, which you can do via a web browser when editing the page that contains that webpart, or via SharePoint Designer, which tends to suck less.

        The other poster, leOrzz, indicated they changed the search for the tag ‘.ms-bodyareacell’ to be ‘.ms-wikicontent’ , so that must be the new tag for SP2013. You said you removed that tag altogether and it still worked, which seems a bit strange.

        Our environment is moving to SP2013 in the new year so I’ll get to try the code changes then.

    3. Hi. I changed this for sharepoint 2013 and work fine. Thanks for all.

      <script type="text/javascript" src="/

      function hideTOC() {
      document.getElementById(“theTOC”).style.display = ‘none’;
      document.getElementById(“show”).style.display = ‘block’;
      document.getElementById(“hide”).style.display = ‘none’;
      }

      function showTOC() {
      document.getElementById(“theTOC”).style.display = ‘block’;
      document.getElementById(“show”).style.display = ‘none’;
      document.getElementById(“hide”).style.display = ‘block’;
      }

      Table of Contents

      [hide]
      [show]

      $(document).ready(function(){
      var L2=0, L3=0, L4=0;
      $(“.ms-wikicontent h1, .ms-wikicontent h2, .ms-wikicontent h3, .ms-wikicontent h4″).each(function(i){
      theLevel=$(this).get(0).tagName;
      if (theLevel==”H2″) {
      L2=L2+1;
      L3=0;
      L4=0;
      theLevelString=””+L2;
      }
      else if (theLevel==”H3″) {
      L3=L3+1;
      L4=0;
      theLevelString=””+L2+”.”+L3;
      }
      else {
      L4=L4+1;
      theLevelString=””+L2+”.”+L3+”.”+L4;
      }
      $(this).attr(“id”, “heading_” + i);
      $(“#theTOC”).append(“” + theLevelString + ” ” +

      $(this).text() + ““);
      });
      });
      hideTOC();

      #wikiTOC {border: 1px black dashed; background-color: whitesmoke; float: left; padding: 10px; padding-top: 0px;}
      #wikiTOC .TOCheader {font-size: 1.1em; font-weight: bold; text-align: center; padding: 5px;}
      #wikiTOC .closehide {font-size: 11px; font-weight: normal;}
      #wikiTOC a[title=H2] {font-size:12px; font-weight: normal;}
      #wikiTOC a[title=H3] {font-size:11px; font-weight: normal; margin-left: 8px;}
      #wikiTOC a[title=H4] {font-size:10px; font-weight: normal; margin-left: 16px;}

      1. Thanks le0rzz.

        I’m moving to SP2013 in the new year and will try your changes then. Looks like MSoft have just changed the ‘.ms-bodyareacell’ tag to ‘.ms-wikicontent’.

Leave a reply to Siva Cancel reply