A L E X   K U Z N E T S O F
Sep 18,2025
Read Time: 2 min

Sanity: Introduction to Portable Text

Key takeaway: Portable Text is a flexible, JSON-based rich text specification that allows you to author structured content once and render it in any format—from HTML and Markdown to mobile and print—without locking you into a single representation.

What Is Portable Text?

Portable Text is a language-agnostic format for representing rich text as structured JSON blocks. Unlike HTML or Markdown, it treats text as an array of content blocks, each with its own style, inline decorators, and annotations.

Core Structure

A Portable Text document is an array of block objects. Each block typically looks like this:

{
  "_type": "block",
  "style": "normal",
  "children": [
    {
      "_type": "span",
      "marks": ["strong"],
      "text": "Example text"
    }
  ],
  "markDefs": []
}

Main Components

Blocks
Blocks are the building blocks of Portable Text. They can represent:

  • Paragraphs
  • Headings (h1, h2, h3, etc.)
  • Blockquotes
  • Lists
  • Custom block types

Styles
Styles map blocks to semantic roles, similar to HTML elements:

  • normal → paragraph
  • h1, h2, h3 → headings
  • blockquote → quotes
  • code → code blocks

Decorators
Decorators apply inline formatting within spans:

  • strong → bold
  • em → italic
  • underline → underline
  • code → inline code

Annotations
Annotations attach rich metadata to text spans, such as links or custom objects:

  • External links (URL)
  • Internal cross-references
  • Custom annotations

Configuring Portable Text in Sanity

Basic Schema

The simplest configuration for a Portable Text field:

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

Advanced Schema

Customize styles, decorators, and annotations:

export default {
  name: 'content',
  type: 'array',
  title: 'Content',
  of: [
    {
      type: 'block',
      styles: [
        { title: 'Normal', value: 'normal' },
        { title: 'Heading 1', value: 'h1' },
        { title: 'Heading 2', value: 'h2' },
        { title: 'Quote', value: 'blockquote' }
      ],
      marks: {
        decorators: [
          { title: 'Bold', value: 'strong' },
          { title: 'Italic', value: 'em' }
        ],
        annotations: [
          {
            title: 'Link',
            name: 'link',
            type: 'object',
            fields: [{ title: 'URL', name: 'href', type: 'url' }]
          }
        ]
      }
    }
  ]
}

Adding Custom Blocks

You can include images, code blocks, and other custom types:

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

Rendering Portable Text

Sanity offers official rendering libraries for multiple frameworks:

  • React: @portabletext/react
  • Vue: @portabletext/vue
  • Svelte: @portabletext/svelte
  • React Native: @portabletext/react-native
  • HTML: @portabletext/to-html

React Rendering Example

import { PortableText } from '@portabletext/react';

const components = {
  types: {
    image: ({ value }) => <img src={value.imageUrl} alt={value.alt} />,
    code: ({ value }) => (
      <pre>
        <code>{value.code}</code>
      </pre>
    )
  },
  marks: {
    link: ({ children, value }) => <a href={value.href}>{children}</a>
  }
};

function MyComponent({ content }) {
  return <PortableText value={content} components={components} />;
}

Advantages of Portable Text

Flexibility and Portability
Content authored once can be output to web, mobile, PDF, or any custom format without rewriting.

Structured Data
JSON blocks make querying and transforming content easy with GROQ or standard JSON tools.

Extensibility
Define custom block types, styles, and annotations tailored to your project’s needs.

Validation and Consistency
Sanity schemas let you enforce content rules and maintain consistency across documents.

Use Cases

  • Blogs and Articles: Rich formatting, embedded images, and links.
  • Documentation: Code blocks, multi-level headings, and cross-references.
  • Omnichannel Content: Serve the same content to websites, mobile apps, and PDFs without loss of structure.
Shared by