GraphQL not returning bullet and link types from Portable Text block

30 replies
Last updated: Jan 14, 2026
All portableText Elements come out in graphql as either on of the following types:
span
,
h2
,
h3
But not as
bullet
and
link
, although they are correctly formatted within Studio.
export default {
  name: 'pageTextSection',
  title: 'Page Text Section',
  type: 'document',
  fields: [
    {
      name: 'body',
      title: 'Body',
      type: 'array',
      of: [{type: 'block'}],
    },
  ],
}
Am I missing something here?
AI Update

You're not missing anything in your schema - this is expected behavior with how Portable Text structures data!

Bullets and links aren't separate block types - they're represented differently in the data structure:

Bullets (List Items)

Bullets are still blocks with _type: 'block', but they have additional properties:

  • listItem: 'bullet' (or 'number' for numbered lists)
  • level: 1 (for nesting level)

In GraphQL, they come through as blocks, not as a separate "bullet" type. You need to check the listItem and level fields on the block to identify them.

Links are stored as annotations in the markDefs array, not as separate block types. The actual link text is still a span with a mark property that references the annotation. The structure looks like:

{
  "_type": "block",
  "children": [
    {
      "_type": "span",
      "text": "click here",
      "marks": ["abc123"]  // references the markDef
    }
  ],
  "markDefs": [
    {
      "_key": "abc123",
      "_type": "link",
      "href": "https://example.com"
    }
  ]
}

How to Handle This in GraphQL

When querying GraphQL, you'll need to:

  1. Look for blocks with listItem and level properties to identify list items
  2. Check the markDefs array on each block for link annotations
  3. Match the marks array on spans to the _key in markDefs to connect linked text to URLs

This is all correctly formatted in Studio because the Portable Text editor understands this structure. Your GraphQL client needs to handle the same relationships when rendering.

I'd recommend using a Portable Text renderer library for your frontend framework to handle this complexity automatically - it will properly parse listItem, markDefs, and all the other Portable Text conventions for you. Check out the guide on presenting block text for more details on rendering Portable Text.

Show original thread
30 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.

Was this answer helpful?