Sanity logosanity.ioAll Systems Operational© Sanity 2026
Change Site Theme
Sanity logo

Documentation

    • Overview
    • Platform introduction
    • Next.js quickstart
    • Nuxt.js quickstart
    • Astro quickstart
    • React Router quickstart
    • Studio quickstart
    • Build with AI
    • Content Lake
    • Functions
    • APIs and SDKs
    • Agent Actions
    • Visual Editing
    • Blueprints
    • Platform management
    • Dashboard
    • Studio
    • Canvas
    • Media Library
    • App SDK
    • Content Agent
    • HTTP API
    • CLI
    • Libraries
    • Specifications
    • Changelog
    • User guides
    • Developer guides
    • Courses and certifications
    • Join the community
    • Templates
Developer guides
Overview

  • Develop with AI

    Best practices

  • Query optimization

    Paginating with GROQ
    High performance GROQ

  • Roles and authentication

    Setting up Single Sign-On with SAML
    Third-Party Login (Deprecated)
    OAuth2
    Set up SSO authentication with SAML and Azure/Entra ID
    Set up SSO authentication with SAML and PingIdentity
    Set up SSO authentication with SAML and JumpCloud
    Reconcile users against internal systems
    Restrict Access to Specific Documents
    Setting up a Default Relay State for IdP Initiated - SAML Logins

  • Structured content

    Scalable navigation patterns
    An opinionated guide to Sanity Studio
    Browsing Content How You Want with Structure Builder
    Deciding on fields and relationships
    Create richer array item previews
    Dynamic folder structure using the currentUser and workflow states
    Create a time duration object field
    Level up Your Edit Modal with Next/Previous Navigation Buttons for Array Items
    Create a “coupon generator” string field input
    Managing redirects with Sanity
    Create a document form progress component
    Create an array input field with selectable templates
    Creating a Parent/Child Taxonomy
    Create interactive array items for featured elements
    Create a visual string selector field input
    Create a survey rating number field input
    How to use structured content for page building
    Create a recycling bin for deleted documents via Sanity Functions

  • Frontend integration

    Add live content to your application
    Forms with Sanity
    Vercel Integration
    Build your blog with Astro and Sanity
    How to implement front-end search with Sanity

  • Ecommerce

    Displaying Sanity content in Shopify
    Sanity Connect for Shopify
    Custom sync handlers for Sanity Connect

  • Integrating with other services

    A/B testing with Sanity and Growthbook
    Cookie consent integrations with Sanity
    Integrating external data sources with Sanity
    Klaviyo (email campaigns)
    Developing with Next.js on GitHub Codespaces

  • Adopting Sanity

    How to pitch Sanity.io to your team
    Convincing your clients to go with Sanity.io, rather than a traditional CMS
    Not-profit plan
    Agencies: Navigating the Spring 2025 Organization Changes
    How to generate massive amounts of demo content for Sanity
    How to implement Multi-tenancy with Sanity

  • GROQ

    GROQ-Powered Webhooks – Intro to Filters
    GROQ-Powered Webhooks – Intro to Projections

  • Portable Text

    Presenting Portable Text
    Add Inline blocks for the Portable Text Editor
    Beginners guide to Portable Text
    How to add custom YouTube blocks to Portable Text
    Converting Inline Styles to Sanity Block Decorators
    Add things to Portable Text
    Change the height of the PTE

  • Community and ecosystem

    Create your own Sanity template
    Community guides
    Community Code of Conduct
    Contribute to the ecosystem

  • Plugin development

    Migrating plugins to support Content Releases

On this page

Previous

Presenting Portable Text

Next

Beginners guide to Portable Text

Was this page helpful?

On this page

  • Adding custom blocks to Portable Text
  • Inline custom blocks - embed content directly into text
  • How will this look in the Portable Text Editor?
  • How does the Portable Text output look like?
  • Resolving author reference in GROQ queries
Developer guidesLast updated September 24, 2025

Add Inline blocks for the Portable Text Editor

Enrich your content and add inline blocks to your Portable Text Editor. This guide takes you from schema to query output

This developer guide was contributed by Saskia Bobinska (Senior Support Engineer).

There are many cases where we want to define specific inline content depending on a user’s country, device, or journey stage. There are ways to do this with variables in PHP and other frameworks. But inline blocks in Portable Text make more possible than the usual variables!

Did you know that you can, for example, dynamically load product prices depending on a user’s location, add any special offers that may apply to them, and add an icon that links to local vendors?

Here is how you can do it!

This uses V3 but can easily be implemented in V2 by using the fields etc. in the old way to define schemas.

Adding custom blocks to Portable Text

You might be familiar with how to add custom blocks for the Portable Text Editor by combining the type: 'block' with other object types like image.

import { defineType } from 'sanity'

export default defineType({
  name: 'content',
  type: 'array',
  title: 'Content',
  of: [
    {
      type: 'block'
    },
    {
      type: 'image'
    }
  ]
})

Inline custom blocks - embed content directly into text

But did you know you can also implement inline blocks by adding the of property and an array of object types to the block object field definition?

Let’s say you wanted to embed a reference to an author in running text. Then, the schema definition would look something like this:

import { defineType } from 'sanity'

export default defineType({ 
  name: 'blockContent', 
  type: 'array', 
  of: [ 
    { type: 'block', 
      of: [ 
        {name: 'authorReference', 
        type: 'reference', 
        to: [{type: 'author'}]
        } 
      ] 
    } 
  ] 
})

How will this look in the Portable Text Editor?

Loading...
How the inline reference to author will look like in the toolbar of the Portable Text Editor

Loading...
When you add an inline block, usually this will open a modal, very similar to annotations.
Loading...
Inline reference to author Saskia Bobinska inside the Portable Text Editor

How does the Portable Text output look like?

As you can see in the JSON below, authorReference is on the same as the rest of the text. This is very different from annotations and their output.

"content": [
    {
      "_key": "f6c1d654f9f4",
      "_type": "block",
      "children": [
        {
          "_key": "887fd31a6817",
          "_type": "span",
          "marks": [],
          "text": "This is how an inline reference to an author, "
        },
        {
          "_key": "39d95d603c1a",
          "_type": "authorReference",
          "_ref": "9b8382ae-69f7-4161-a0e2-e8a86b15d616"
        },
        {
          "_key": "0db93e64f0ed",
          "_type": "span",
          "marks": [],
          "text": ", would look like."
        }
      ],
      "markDefs": [],
      "style": "normal"
    }
  ]

Resolving author reference in GROQ queries

Now that we have the author reference embedded inline with the text we need to be able to resolve the reference so we can serialise the Portable Text output in our front-end.

In order to do so, we have to make sure, we resolve authorReference in our query:

*[_type == 'post']{
  ..., 
  // get the content array 
  content[]{
    // if the type is block...
    _type == 'block' => {
    ..., 
    // get the childrens array, and... 
    children[]{
      ...,
      // if a childrens type is our author reference,...
      _type == 'authorReference' => {
      ...,
      // create a new key value pair named "authorName" with the value name value of the referenced author document
      "authorName": @->.name
      }
      }
    }
  }
}

Output:

...,
{
  "_key": "9d95d603c1a",
  "_ref": "9b8382ae-69f7-4161-a0e2-e8a86b15d616",
  "_type": "authorReference",
  "authorName": "Saskia Bobinska"
},
...
import { defineType } from 'sanity'

export default defineType({
  name: 'content',
  type: 'array',
  title: 'Content',
  of: [
    {
      type: 'block'
    },
    {
      type: 'image'
    }
  ]
})
import { defineType } from 'sanity'

export default defineType({ 
  name: 'blockContent', 
  type: 'array', 
  of: [ 
    { type: 'block', 
      of: [ 
        {name: 'authorReference', 
        type: 'reference', 
        to: [{type: 'author'}]
        } 
      ] 
    } 
  ] 
})
Screenshot of a Portable Text Editor in dark mode with a "Reference to author" button in the toolbar
Screenshot showing, that adding an inline block, usually will open a modal, very similar to the way annotations work
Screenshot of Inline reference to author Saskia Bobinska inside the Portable Text Editor
"content": [
    {
      "_key": "f6c1d654f9f4",
      "_type": "block",
      "children": [
        {
          "_key": "887fd31a6817",
          "_type": "span",
          "marks": [],
          "text": "This is how an inline reference to an author, "
        },
        {
          "_key": "39d95d603c1a",
          "_type": "authorReference",
          "_ref": "9b8382ae-69f7-4161-a0e2-e8a86b15d616"
        },
        {
          "_key": "0db93e64f0ed",
          "_type": "span",
          "marks": [],
          "text": ", would look like."
        }
      ],
      "markDefs": [],
      "style": "normal"
    }
  ]
*[_type == 'post']{
  ..., 
  // get the content array 
  content[]{
    // if the type is block...
    _type == 'block' => {
    ..., 
    // get the childrens array, and... 
    children[]{
      ...,
      // if a childrens type is our author reference,...
      _type == 'authorReference' => {
      ...,
      // create a new key value pair named "authorName" with the value name value of the referenced author document
      "authorName": @->.name
      }
      }
    }
  }
}
...,
{
  "_key": "9d95d603c1a",
  "_ref": "9b8382ae-69f7-4161-a0e2-e8a86b15d616",
  "_type": "authorReference",
  "authorName": "Saskia Bobinska"
},
...