Skip to main content

Command Palette

Search for a command to run...

Custom Table of Contents for SharePoint Page Libraries - JSON View Formatting

Create a Table of Contents for Site Page libraries in SharePoint. Easily implement site-wide, via web parts. Supports auto updates and additions.

Updated
Custom Table of Contents for SharePoint Page Libraries -  JSON View Formatting

Background

JSON view customizations in SharePoint Online are usually created for local use within a list or library. The view described in this article, however, is intended for web parts - altering how Site Page contents are displayed across pages and templates.

Site Page library custom Table of Content view within web part

Site Page Table of Contents - Example

Automatic Updates

Changes and additions to the Site Page library are automatically reflected everywhere the TOC view is currently implemented via web part.

Even when installed across hundreds of pages, updates require just a single action at the source library. This can be quite useful for wiki-style and informational sites… especially ones that will evolve and grow over time.

💡
The TOC view is to meant to augment (but not replace) site and hub navigation

Implementing

Note: Don’t let the length of this section fool you. These steps are not particularly complicated or time-consuming. I always try to include extra detail, as a fair amount of visitors stumble across this blog. 👍

Site Page Library - Columns

Several custom columns are needed to define the TOC structure. These columns can be created directly within the Site Pages library (easiest) or within the corresponding content type (more flexible).

🔷 Sort Order

💡
Technically, this step is optional. You can rely on alpha sort (or another system column) for your TOC view. However, a custom sort method (1) enables indentation to work predictably. It also (2) prevents ambiguity, like the page titled Home showing up in the middle (after items A-G), for example.

Create a number column, which will be used to define the TOC page sequence. This field is not referenced by the formatting JSON, so name it as you wish:

Column setup for Order field

The above settings will work fine, but you don’t have to strictly adhere to them. You might want to disable enforce unique values, for example, as it can be a minor pain later on, without much benefit.

🔷 Indentation

Create another number column, which will define the hierarchy within the TOC. Name it Indent, to align with field references in the formatting JSON:

Column setup for Indent field
Setting a default value is recommended. The JSON formatting expects indentation values of 0, 2, 4 or 6

Site Page Library - Custom View(s)

🔷 Table of Contents (display view)

This view will (later) receive the custom JSON formatting.

  1. Create a new public view (call it TOC or something similar)

  2. Include these columns:

    1. Indent

    2. Name (for use in forms)

    3. Title

  3. Set the Sort parameter to use the custom Order column (assuming you created it):

  4. Set the Filter criteria to only include items with an Indent value:

    💡
    Ignore the lowercase “i” in the screenshot above - field name is Indent (woops)
    You can add a boolean column (or similar) if you’d like more control over item visibility in the TOC. Indent works fine, but if that column has a default value set, new pages will show up instantly.

🔷 Table of Contents (management view)

Optional step, but you may want to do one of these:

  1. Add the new library columns to the All Pages system view (and make it the library default, instead of the clumsy, grouped By Author view).

  2. Create a new view for working with TOC site page metadata (that won’t receive the JSON formatting)

Modified All Pages system view

Example modified All Pages view

Site Page Library - Bulk Edit Existing Pages

If there are existing pages in the library, use quick edit to assign column values (Order, Indent) to the pages you want included in the TOC.

Also, make sure each page has a Title value.

Column Usage Tips: Indent

The indent value affects the padding of TOC items and for the more indented ones, font size.

Indent value conditional formatting
💡
Note: the TOC items will not display the Indent value, as seen above. That was added temporarily for illustration purposes.

Column Usage Tips: Order

Give yourself plenty of “space” when assigning Order values. Space them apart by counts of 10-100, to provide flexibility for reordering or adding later.

If you number each page sequentially (1,2,3…) you might need to re-number a bunch of Order values to insert new pages where you want them, later.

All Pages library view, showing Order values

View Formatting JSON

Details / Notes

Overall, it’s a decent custom view - not a perfect one.

  • Much of the styling in this JSON is done using classes, but there are some fixed values in the mix (margins, e.g.)

  • There are probably some minor opportunities to improve HTML / flexbox stuff, too

  • The key lines for conditional styling are 20, 39 and 45

    • Some of those conditions resolve identically. Those are legacies from development, left in to allow for future customization.
{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json",
  "schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json",
  "target": "_self",
  "debugMode": false,
  "hideColumnHeader": true,
  "hideSelection": true,
  "rowFormatter": {
    "elmType": "a",
    "attributes": {
      "class": "ms-fontColor-themeDarker ms-fontColor-themeDarker--hover",
      "href": "=@currentWeb + '/SitePages/' + [$FileLeafRef]",
      "target": "_self"
    },
    "style": {
      "text-decoration": "none",
      "border": "none",
      "cursor": "pointer",
      "margin-bottom": "2px",
      "margin-left": "=if([$indent] == 2,'12px', if([$indent] == 4, '24px', if([$indent] == 6,'36px', '0px')))",
      "padding": "2px",
      "overflow": "hidden",
              "width": "100%",
              "max-width": "280px"
    },
    "customRowAction": {
      "action": "defaultClick"
    },
    "children": [
      {
        "elmType": "div",
        "style": {
          "display": "flex",
          "flex-direction": "column",
          "align-items": "baseline",
          "flex-wrap": "wrap",
          "box-sizing": "border-box",
          "border-width": "0px",
          "border-left-width": "=if([$indent] == 0,'3px', if([$indent] == 2, '3px', '3px'))",
          "border-style": "solid",
          "padding-left": "4px",
              "width": "100%"
        },
        "attributes": {
          "class": "=if([$indent] == 0,'ms-fontSize-mPlus ms-borderColor-themeDark', if([$indent] == 2, 'ms-fontSize-mPlus ms-borderColor-themeSecondary', if([$indent] == 4,'ms-fontSize-m ms-borderColor-themeLight', 'ms-fontSize-m ms-borderColor-themeLighter'))) + ' ms-bgColor-themeLighter--hover'"
        },
        "children": [
          {
            "elmType": "div",
            "style": {
              "line-height": "1.0em",
              "margin": "2px 0",
              "text-align": "left"
            },
            "txtContent": "[$Title]"
          }
        ]
      }
    ]
  }
}

Document Library Web Part

Add a Document Library web part onto a site page and configure it like this:

Document Library web part setup and config
Keep in mind, you can also add the web part to page templates. This is a great way to rapidly propagate the web part and view across a site in a consistent manner.

By this point, you should be in business.

If this worked out for you, or if you have any difficulties, please drop me a note in the comments.