Unlock seamless workflows and faster delivery with our latest releases - Join the deep dive

Can you nest PortableText JSX elements via the components property in @portabletext/react?

7 replies
Last updated: Feb 7, 2023
have a
@portabletext/react
question — is it possible to nest
<PortableText />
JSX elements via the
components
property? My schema structure is as follows: I have an
array
of
block
and
imageWithCaption
fields, the
imageWithCaption
field is an
image
with subfield of
caption
which is also a
PortableText
block field.
I’ve attempted this already and nothing shows up where
<PortableText />
is supposed to be rendered so this seems like a no — but I’m curious is anyone has a similar use case and attempted other implementations of this.

// bodyText.ts
import linkObject from 'schemas/objects/link';
export default defineType({
  name: 'bodyText',
  title: 'Body Text',
  type: 'array',
  description: 'Enter the body text of this field note.',
  of: [
    {
      type: 'imageWithCaption',
    },
    {
      type: 'block',
     ...
    },
  ],
});

// imageWithCaption.ts
export default defineType({
  name: 'imageWithCaption',
  title: 'Image',
  type: 'image',
  options: {
    storeOriginalFilename: true,
  },
  fields: [
    {
      name: 'caption',
      title: 'Caption',
      type: 'caption',
      description: 'Enter the caption for this image.',
    },
    ...
  ],
});

// caption.ts
export default defineType({
  name: 'caption',
  title: 'Caption',
  type: 'array',
  of: [
    {
      type: 'block',
      styles: [{ title: 'Normal', value: 'normal' }],
      marks: {
        decorators: [
          { title: 'Strong', value: 'strong' },
          { title: 'Emphasis', value: 'em' },
          { title: 'Underline', value: 'underline' },
        ],
      },
      lists: [],
    },
  ],
});
Feb 7, 2023, 3:51 PM
Yes, you can nest portable text renderers. It’s actually a pretty common case, especially for your use case for instance.
Feb 7, 2023, 5:41 PM
I have something like this in one of my projects (trimmed down to the bone for simplicity):

const document = {
  type: 'document',
  fields: [
    {
      type: 'array',
      of: [
        // Generic portable text stuff
        { type: 'block' },
        // The custom type
        { type: 'object', fields: [
          // … which has portable text has one of its field
          { type: 'array', of: [ { type: 'block' } ] }
        ] }
      ]
    }
  ]
}
Feb 7, 2023, 5:45 PM
hi kitty! that’s great news
Feb 7, 2023, 5:46 PM
it’s possible to render this with
@portabletext/react
?
Feb 7, 2023, 5:46 PM
Yeah, same thing on the frontend, you can have nesed renderers. 🙂
Feb 7, 2023, 5:46 PM
Something like this:
<PortableText
  value={props.value}
  components={{
    types: {
      imageWithCaption: (props) => (
        <figure>
          <img src={props.value.src} alt='' />
          <figcaption>
            <PortableText value={props.value.caption} />
          </figcaption>
        </figure>
      )
    }
  }}
/>
Feb 7, 2023, 5:48 PM
perfect i’ll give that a try
Feb 7, 2023, 6:01 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?