Best way to query GROQ for blog body with list, marks, and formatting?
When querying Portable Text content in GROQ, you typically don't need to manually map through body.children - you just query the field normally and handle the rendering in your frontend code. Let me explain the best approaches:
Querying Portable Text in GROQ
In your GROQ query, you can simply include the body field as-is:
*[_type == "post"] {
title,
body
}This returns the complete Portable Text structure (blocks, marks, annotations, etc.) which you then render in your frontend.
Rendering the Content
The easiest way to handle Portable Text is to use Sanity's official rendering libraries for your framework:
For React/Next.js:
import {PortableText} from '@portabletext/react'
<PortableText value={post.body} />For other frameworks:
- @portabletext/svelte for Svelte
- @portabletext/vue for Vue
- @portabletext/solid for Solid
These libraries automatically handle all the block types (paragraphs, lists, marks like bold/italic, etc.) without you needing to manually iterate through children.
If You Need Plain Text
If you actually need to extract just the plain text (for search, previews, or meta descriptions), use the pt::text() function directly in your GROQ query:
*[_type == "post"] {
title,
"plainText": pt::text(body)
}This strips all formatting and gives you clean text without any manual mapping.
Custom Rendering
If you need custom styling for specific marks or blocks, you can pass custom components to the PortableText renderer:
<PortableText
value={post.body}
components={{
marks: {
strong: ({children}) => <strong className="font-bold">{children}</strong>
},
block: {
h1: ({children}) => <h1 className="text-4xl">{children}</h1>
}
}}
/>Bottom line: Use the official Portable Text rendering libraries rather than manually mapping through the structure. They handle all the complexity for you!
Show original thread10 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.