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.

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.

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.
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
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:

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:

Site Page Library - Custom View(s)
🔷 Table of Contents (display view)
This view will (later) receive the custom JSON formatting.
Create a new public view (call it TOC or something similar)
Include these columns:
Indent
Name (for use in forms)
Title
Set the Sort parameter to use the custom Order column (assuming you created it):

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:
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).
Create a new view for working with TOC site page metadata (that won’t receive the JSON formatting)

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.

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.

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:

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.





