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.