📆 Don't miss our Sanity Showcase virtual meetup on March 20th!

Discussion comparing Delta and Portable Text formats for storing rich text

4 replies
Last updated: Oct 1, 2021
I've been looking into sanity recently and was wondering what people's thoughts were on portable text. I've used quill before, and after a few hours of research and thought, I still feel like quill's delta is easier to understand and serialize over portable text. Has anyone else researched this and/or have input?
Sep 30, 2021, 1:56 AM
To clarify, I am not focusing so much on the quill's implementation of deltas or sanity's implementation of portable text. Instead, I am talking about the medium of storing rich text as a whole.
Sep 30, 2021, 3:09 AM
I've given a brief example of both formats that depicts custom blocks and custom inline text along with plain and formatted text.
Delta:

{ 
  ops: [
    {
      insert: "text",
      attributes: { 
       bold: true 
      }
    },
    {
      insert: " and more text\n..."
    },
    {
      insert: "and still more",
      attributes: {
        link: "<https://somelink.com|https://somelink.com>",
        target: "_blank"
      }
    },
    {
      insert: "\n",
      attributes: {
        paragraph: true
      }
    },
    {
      insert: {
        image: "<https://imagelink.com|https://imagelink.com>"
      },
      attributes: {
        b: true,
        c: 100,
        d: "data"
      }
    }
  ]
}
Portable Text:

[
  {
    _type: "block",
    style: "normal",
    children: [
      {
        _type: "span",
        text: "text",
        marks: ["bold"]
      },
      {
        _type: "span",
        text: " and more text\n...",
        marks: []
      },
      {
        _type: "span",
        text: "and still more",
        marks: ["random1"]
      }
    ],
    markDefs: [
      {
        _key: "random1",
        _type: "link",
        href: "<https://somelink.com|https://somelink.com>",
        target: "_blank"
      }
    ]
  },
  {
    _type: "image",
    src: "<https://imagelink.com|https://imagelink.com>",
    b: true,
    c: 100,
    d: "data"
  }
]
As you can see, deltas seem to have the advantage when it comes to the availability of attributes. However, portable text does do a better job of handling block styles (it is much easier to enforce block styles when a block must exist for children to be attached, whereas a new line could easily be forgotten).

I do wonder if there is a way to combine the benefits of both specs, though I think there is certainly something to be said about the readability and parseability of deltas as compared to portable text. The fact that it is one dimensional as compared to the two dimensions created by block-children pairs helps.
Sep 30, 2021, 3:25 AM
I've worked with prosemirror before and found it slightly easier to read and serialise than portable text. Here's a sample:
{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "This is the "
        },
        {
          "type": "text",
          "marks": [
            {
              "type": "strong"
            }
          ],
          "text": "first"
        },
        {
          "type": "text",
          "text": " sentence in the "
        },
        {
          "type": "text",
          "marks": [
            {
              "type": "em"
            }
          ],
          "text": "first"
        },
        {
          "type": "text",
          "text": " paragraph."
        }
      ]
    },
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "This is the second paragraph."
        }
      ]
    }
  ]
}
To me one of the main issues i've encountered with serialising portable text is the inconsistencies in storing
marks
and
markDefs
. I don't see the benefit of storing "default" marks as strings, and "custom" marks as references to an array in an outer scope. The inconsistency here is that what portable text defines as "default marks" are specific semantic references to html, and require special handling when working with custom serialisers. There's a similar issue opened here on the nomenclature of styles , which also heavily relies on references to html, all of which doesn't align with the goal of creating an "agnostic abstraction of rich text". Prosemirror's document model is more consistent in the sense that all marks are stored as objects with a type key without any reference to a specific implementation, because ideally the format could be used in a context where HTML is not used at all. Lastly, the fact that the spec has not been revised in almost 4 years is also something to consider when comparing different formats.
Oct 1, 2021, 4:01 PM
Lastly, the fact that the spec has not been revised in almost 4 years is also something to consider when comparing different formats.
We’re working on it!
Oct 1, 2021, 5:05 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?

Related answers

Get more help in the community Slack

TopicCategoriesFeaturedRepliesLast Updated
Rendering nested block contentJan 18, 2021
Warning: Data for Page Exceeds the Threshold of 128 kBAug 17, 2022
Custom Document Views - Is it Even Possible to Use the Structure Builder?Apr 21, 2022
GraphQL query resolving references on a _raw field in GatsbyMay 17, 2022
How to populate a list of values in a Sanity schema using a separate fileSep 6, 2021
How to fetch an array of images using groq in Sanity.ioMay 21, 2023
Is there a way to write a groq query that checks if a boolean is true, and if so, returns an array of referenced documents?...Feb 1, 2021
Error: unable to resolve image URL from source (undefined)Sep 11, 2022
Examples of customized dashboards/admin pages and the queryable feature of Portable Text.May 1, 2020
Extracting referenced images from an object array in Sanity.ioMay 17, 2020

Related contributions

Turbo Start Sanity
- Template

The battle-tested Sanity template that powers Roboto Studio's websites

Go to Turbo Start Sanity

Schema UI - Next.js Sanity Starter
- Template

A Next.js starter template with Next.js 15, Tailwind CSS, shadcn/ui, and Sanity CMS with Live Editing. Get production-ready React components with matching Sanity schemas and queries. Build dynamic pages faster while keeping full control over customization.

Serge Ovcharenko
Go to Schema UI - Next.js Sanity Starter

The Swaddle
- Made with Sanity

A new brand identity to represent a more mature company, to signify The Swaddle’s evolution from publisher to production house, combined with an easier to navigate platform that can surface multiple content types - drawing readers through The Swaddle’s content offering.

Nightjar
Go to The Swaddle