How to create a custom data structure for quotes in Portable Text

9 replies
Last updated: Aug 22, 2021
What you describe here is essentially a data structure that consists of a quote (a text string) and an author name (a text string). Portable Text lets you insert custom data structures in between paragraphs (which also are their own objects really. The way I’d do this would be to first define a new object type:
// quote.js
export default {
  name: 'quote',
  type: 'object',
  title: 'Quote',
  fields: [
    {
      name: 'text',
      type: 'text', // <= This can also be a Portable Text field
      title: '',
    },
    {
      name: 'author',
      type: 'string', // <= This could be a reference to an author document type, if you had that
      title: 'Author',
    }
  ]
}
Remember to import this into your schemas in
schema.js
and then you can add the following to your Portable Text field (I’ve made a simple one here:
// portableText.js
export default {
  name: 'portableText',
  type: 'array',
  title: 'Portable Text',
  of: [
    {
      type: 'block',
    },
    {
      type: 'quote',
    }
  ]
}

Aug 22, 2021, 9:13 AM
Come think of it, you could also add support for an URL in the quote (reasoning in a bit):
// quote.js
export default {
  name: 'quote',
  type: 'object',
  title: 'Quote',
  fields: [
    {
      name: 'text',
      type: 'text', // <= This can also be a Portable Text field
      title: '',
    },
    {
      name: 'author',
      type: 'string', // <= This could be a reference to an author document type, if you had that
      title: 'Author',
    },
    {
      name: 'url',
      type: 'url',
      title: 'URL',
      description: 'Source on the web', 
     }
  ]
}

Aug 22, 2021, 9:16 AM
Amazing! This was really helpful and I’ve already got it set up in my codebase now. Very quick and easy to implement 😀👍
Aug 22, 2021, 9:17 AM
And the serializer for this in the frontend can be something like this:
// portableText.js
const serializers = {
  type: {
    quote: ({ text, author, url }) => {
      return (
        <figure>
          <blockquote cite={url}>
            {text}
          </blockquote>
          {author && <figcaption>{author}</figcaption>}
        </figure>
      )
    }
  }
}
Just went on a
🐰 🕳️ on how to properly markup this with HTML5. Not super obvious tbh. This seems like a reasonable solve .
Aug 22, 2021, 9:25 AM
Any idea why the above code wouldn’t work?
I’m getting the data through in my block content as I can see the quote in GrapQL.

When I add the word ‘test’ in after the {text} variable, in the serializer, that’s showing up i.e.:

<blockquote>{text} test</blockquote>
But the actual text and author is not showing up.

The serializers are in a separate js file and are piped into my block content like:

<BlockContent serializers={serializers} />
Aug 22, 2021, 9:39 AM
oh, I forgot the pattern should be
// portableText.js
const serializers = {
  type: {
    quote: ({node: { text, author, url }}) => {
      return (
        <figure>
          <blockquote cite={url}>
            {text}
          </blockquote>
          {author && <figcaption>{author}</figcaption>}
        </figure>
      )
    }
  }
}
That is including
node
in
({node: { text, author, url }})
Aug 22, 2021, 9:44 AM
sorry about that
Aug 22, 2021, 9:44 AM
Lovely, that’s working now. Thanks again, this was really helpful 👍
Aug 22, 2021, 9:46 AM

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?