Sekrab Garage

Sanity.IO Tip

Querying GROQ for table of contents

Tip December 26, 22
Subscribe to Sekrab Parts newsletter.

A nice tip I came across when creating a Table of Contents based on H2 elements in an article on Sanity.io site using GROQ statements. Instead of serializing the content and then using DOM to find the H2 elements post-rendering, I adjusted the GROQ statement to get me the H2 elements in the body, in a separate array.

*[slug.current == "${slug}"&&_type=="post"] | order(publishedAt desc) 
{
  publishedAt, _id, 
  // ... other projections 
  body[]{...} 
  // then this: get body's children where style of child is "h2", 
  // then project to text property only
  'toc': body[style == 'h2']{ 
    'text': children[0].text 
  } 
}[0]

The body property is the field that holds the rich text (portable text in Sanity), and it is made up of arrays, each having a style property, which contains the HTML style used to generate the block. You can use any query depending on what you need to attain, here is a query cheat sheet.

The children is the sub-property of h2 and I know for a fact it has one element, you could have a different setup so take notice. That child has a property: text, and that is what I aim for.

Afterwards; I can set up the slug function locally, then post-process the H2 elements to have the id property set up as well. From that point forward it’s just vanilla.

Twenty-two is over.