48

I would like to have the Table of Contents only include Heading 1 and not any of the others. Is there a way to set the table to contents to NOT include certain headings?

1
  • 2
    I thought MS-Word was bad. Did google look at what MS was doing and mistakenly interprete it as "do a very bad job of things (on purpoise)." Aug 7 at 21:20
25

Unfortunately Google Docs does not support hiding specific heading levels.

The only "solution" would be to change the headers you want to hide to the "Normal" style, then manually set the font formatting for each heading.

The only way to avoid all headings from being added to the TOC is to manually apply the style you want rather than using the set styles. Change those headers to "Normal" style by select each one individually and pressing Ctrl + \ (Control plus the backslash key). This will remove the formatting. Then manually add the point size, font, and bolding that you want.

To easily copy formatting from one place to another, you can use the Paint Tool. So once you manually change one heading, you can use the Paint Tool to change others that are the same level heading.

- Source: Google Docs Forums: How to show only Heading 1 in table of contents

1
  • Google could have easily solved this issue by allowing to opt styles to be included or not included in the ToC. Also They could allow users to add a limited number of custom styles.
    – NurShomik
    Nov 4 at 18:47
21

What I did to solve the problem which is probably doc specific, but I was using H1 through H3, what would have been H4 I didn't want to show up in the TOC. I converted all the H4's to Subtitles, then styled Subtitles the way I wanted it.

Subtitles don't show up in the TOC.

How to convert all headings into another heading:

3
  • 4
    I have to hold my nose to upvote this, because it's such a hack, but it seems there's no better alternative. Thanks @donnoman!
    – yoyo
    Feb 6 '20 at 18:06
  • 4
    WHY Google?? WHY!!!1!11!!1one!!?
    – Adrian
    Apr 21 '20 at 21:44
  • Clearly this is the best alternative because it allows you to keep updating both Normal and Subtitle, without interference (when setting a specific subtitle to become the default subtitle format.
    – Guy
    Aug 2 at 6:08
20

The previous answers suggests setting the style of headers to "Normal" and manually setting their style to look like a header. If you do so, you will lose the ability to link to that header from within the document.

It looks like you can actually manually delete items from the table of contents. I think that's a simpler approach.

2
  • 13
    Yet then you'll have to do this each time you update the table of content.
    – Royi
    Sep 27 '17 at 16:53
  • 9
    Also, when inserting the table of contents, the page numbers are calculated. So if your table of contents with the extra headings is moving things around, the page numbers will be wrong after deleting the extra lines.
    – Laura
    Oct 11 '17 at 19:24
4

Table of contents in Google Docs really is very half baked.

The only way to select header levels or to change the formatting from defaults is to REDO any such action(s) MANUALLY after every time the table has been updated. But, to the point made by "Laura" earlier in this thread, that also does not work as the page numbering is calculated right after the table of contents have been inserted and is thereby impacted by the height of the table in its default format. So here is (sadly) what you need to do to have a controlled look of your Google Docs table of content as far as I have been able to take it:

  1. Finish your text.
  2. Insert an empty page for as a place holder for the table of content at the desired place in the document.
  3. Append a blank page after the very last character of the document and insert the table of content there
  4. Do whatever modifications necessary to the table of content (manually)
  5. Manually cut the updated table of contents from the last page and paste it to the previously created place holder page.

This works but it makes you cry... :(

3

From what I can, tell this action is impossible on Google Docs, as other answers have mentioned. However, it would appear that there is another way if you have access to Microsoft Word:

Export the document into a .docx from Google Drive, which can be done when selecting what form you wish to download the document in. Then open this in Word and alter the table of contents using the following guide: https://support.office.com/en-us/article/format-or-customize-a-table-of-contents-9d85eb9c-0b55-4795-8abb-a49885b3a58d#layout

Guide Outline:

  • Select the drop down list from References>Table of Contents from the top bar.
  • Select Custom Table of Contents... from the list.
  • To change the number of levels displayed in your table of contents, click Show levels, and then click the number of levels you want.

I haven't tested this so I'll edit the answer with more feedback.

1
  • 3
    The hack is to just dump google docs! Love it!
    – Adrian
    Apr 21 '20 at 22:08
3

Yes, there's a workaround for this, and you can keep your heading structure.

  1. At the top of your doc, write out the text that you want to show in your table of contents. For example Chapter 1, Chapter 2
  2. Select the first phrase, and make it a hyperlink.
  3. You'll see options for the link, including selecting an existing heading.
0

I have really tried to achieve a better solution for this and got a bit further. I think it is as far as you can get without Google addressing the shortcomings properly. My solution is not great but not entirely appalling. The customized TOC is designed in a separate Google Doc (like a template) and is fulfilled with data and added to the actual document by a script.

Shared a google doc that explains the solution and that also can be used for testing the solution. https://docs.google.com/document/d/1mlJ3rI04isifgncHHP0VWhO8NEmt395Re8lapuTcG3w

The code here (also in the doc):

function onOpen() {
  DocumentApp.getUi()
    .createMenu('My menu')
    .addItem('Custom Table of Contents', 'customTableOfContents')
    .addToUi();
}

function customTableOfContents(){
  var ui = DocumentApp.getUi();  

  //fetch content for the toc
  var textDoc = DocumentApp.getActiveDocument();
  var tocData = getTocData(textDoc);
  if (!tocData.content) {
    ui.alert(tocData.alert);
    return;
  }
  
  //fetch the "style sheet" for the toc and render the content accordingly
  var styleDoc = DocumentApp.openById('1chKuIuJDpQJEcHqn2AW1-W6exDyiknKLrmBXX-3KEDs');
  var renderResult = renderToc(textDoc,styleDoc,tocData.content);
  if (!renderResult.success) {
    ui.alert(renderResult.alert);
    return;    
  }

  //clean up empty rows at document end
  var textDocBody = textDoc.getBody();
  var lastElement = textDocBody.getChild(textDocBody.getNumChildren()-2);
  while (lastElement.getText() == "") {
    textDocBody.removeChild(lastElement);
    lastElement = textDocBody.getChild(textDocBody.getNumChildren()-2);
  }

  if (tocData.dataCollectionStep == 1) {
  //position cursor at the end of the document, prompt user to insert a native table of content
  //and to run the function again.
    var position = textDoc.newPosition(textDocBody.getChild(textDocBody.getNumChildren()-1), 0);
    textDoc.setCursor(position);    
    ui.alert(tocData.alert);
    return;
  }
  
  //we are done!
  if (renderResult.customTocPosition > 0) {
    var position = textDoc.newPosition(textDocBody.getChild(renderResult.customTocPosition), 0);
    textDoc.setCursor(position);
  }
}

function getTocData(doc){
  //build an array of data for the toc
  var docBody = doc.getBody();
  var paragraphs = docBody.getParagraphs();
  var statusMessage;
  var nativeToc;
  var dataCollectionStep = 0;
  try {
    //if a native table of contents exists we assume we are running the function for the second time
    dataCollectionStep = 2;
    nativeToc = docBody.findElement(DocumentApp.ElementType.TABLE_OF_CONTENTS).getElement().asTableOfContents();
  } catch(e) {
    //if no native table of content exists we assume we are running the function for the first time
    dataCollectionStep = 1;
    statusMessage = 'Table of content has been generated but is missing page references and interactive links.' + String.fromCharCode(10) + 
      'To add the missing parts, please select "Table of content" from the "Insert" menu.' + String.fromCharCode(10) + 
      'Then run the "Custom table of content" again.';
  }
  
  var customTocData = [];
  for(var i=0;i<paragraphs.length;i++) { 
    if (paragraphs[i].getText().trim() == "") continue;
    if (paragraphs[i].getHeading() == DocumentApp.ParagraphHeading.NORMAL) continue;
    if (paragraphs[i].getHeading() == DocumentApp.ParagraphHeading.SUBTITLE) continue;
    if (paragraphs[i].getHeading() == DocumentApp.ParagraphHeading.TITLE) continue;

    if (dataCollectionStep == 2) {
      //extracting url-data and page numbers from the native table of contents 
      var nativeTocRecord = nativeToc.getChild(customTocData.length).asParagraph();
      var textAndPage = nativeTocRecord.getText().split(String.fromCharCode(9));        
      if (paragraphs[i].getText().trim() != textAndPage[0]) {
        statusMessage = "Error at row " + i + String.fromCharCode(10) + 'Please manually refresh the table of contents and try again!';
        return {
          content: null,
          dataCollectionStep : dataCollectionStep,
          alert: statusMessage
        };
      }
    }
    customTocData.push({
      heading : paragraphs[i].getHeading(),
      description : paragraphs[i].getText(),
      hyperlink : (dataCollectionStep == 2) ? nativeTocRecord.getChild(0).asText().getLinkUrl(2) : "",
      page : (dataCollectionStep == 2) ? textAndPage[1] : "N/A"
    });
  }
  //removing the native table of contents
  if (dataCollectionStep == 2) docBody.removeChild(nativeToc);
  return {
    content: customTocData,
    dataCollectionStep : dataCollectionStep,
    alert: statusMessage
  };
}

function renderToc(textDoc,styleDoc,tocData){
  var textDocBody = textDoc.getBody();
  var styleHeaderText = styleDoc.getBody().getChild(0).getText().trim().toUpperCase();
  var styleTable = styleDoc.getBody().getChild(1).asTable();
  var customToc;
  var tocIdx = -1;
  
  var featuredHeadings = [];
  for (var i=0;i<styleTable.getNumRows();i++){
    var str = styleTable.getRow(i).getCell(0).getText().trim().toUpperCase();
    switch(str){
      case "FIRST LEVEL" : featuredHeadings.push(DocumentApp.ParagraphHeading.HEADING1);break;
      case "SECOND LEVEL" : featuredHeadings.push(DocumentApp.ParagraphHeading.HEADING2);break;
      case "THIRD LEVEL" : featuredHeadings.push(DocumentApp.ParagraphHeading.HEADING3);break;
      case "FOURTH LEVEL" : featuredHeadings.push(DocumentApp.ParagraphHeading.HEADING4);break;
      case "FIFTH LEVEL" : featuredHeadings.push(DocumentApp.ParagraphHeading.HEADING5);break;
      case "SIXTH LEVEL" : featuredHeadings.push(DocumentApp.ParagraphHeading.HEADING6);break;
    }
  }
  //locate where to insert the custom Table of Contents, delete the current of if there is one and add an empty table element.
  //then copy the attributes from the table element in the style doc
  for(var i=0;i<textDocBody.getParagraphs().length;i++){
    //the below assumes that the text doc has a header paragraph with the same text (i.e "Table of content") as the header for the table in the style doc 
    if (textDocBody.getParagraphs()[i].getText().trim().toUpperCase() == styleHeaderText) {
      tocIdx = i+1;
      if (textDocBody.getChild(tocIdx).getType() == DocumentApp.ElementType.TABLE) textDocBody.removeChild(textDocBody.getChild(tocIdx))
      customToc = textDocBody.insertTable(tocIdx).asTable();
      break;
    }
  }
  if (!customToc){
    var errorMessage = "Can not figure out where to insert the Table of Contents. Please check that there is a header for it in the text document.";
    return {
      success : false,
      customTocPosition : tocIdx,
      alert : errorMessage
    }
  }
  customToc.setAttributes(styleTable.getAttributes());

  for (var i=0;i<tocData.length;i++){
    var templateRowIdx = featuredHeadings.indexOf(tocData[i].heading);
    if (templateRowIdx < 0) continue;

    var styleRow = styleTable.getRow(templateRowIdx);    
    var destinationRow = customToc.appendTableRow(styleRow.copy());

    var destinationCell1 = destinationRow.getCell(0);
    destinationCell1.setText(tocData[i].description);
    //tablerow.copy() does not include the cell width of the copied child cells. Below is a hack to work around that...
      destinationCell1.setWidth(styleRow.getCell(0).getWidth());
    //setLinkUrl forces blue color and underline to text. Below is a hack to work around that...
      var underline = destinationCell1.isUnderline();
      var foregroundColor = destinationCell1.getForegroundColor();
      destinationCell1.setLinkUrl(tocData[i].hyperlink);
      destinationCell1.setUnderline(underline);
      destinationCell1.setForegroundColor(foregroundColor);

    var destinationCell2 = destinationRow.getCell(1);
    destinationCell2.setText(tocData[i].page);
    //tablerow.copy() does not include the cell width of the copied child cells. Below is a hack to work around that...
      destinationCell2.setWidth(styleRow.getCell(1).getWidth());
  }
  return {
    success : true,
    customTocPosition : tocIdx,
    comment : ''
  }
}
0

Another option for the non-developers. I bookmarked the item and used normal text. This will allow me to link within the document without the items appearing in the Table of Contents. You can add manual formatting styles if need be to keep consistent.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.