Using PortableText with defined types in components for a schema with a hero object inside a parent Portable Text array.

24 replies
Last updated: Feb 17, 2023
Hello!I am trying to se PortableText for this query:
I don't know how can I define the
hero
and
content
types in my components options.To be more specific, I want to define
hero
and
content
as JSX elements
AI Update

Based on your question, it sounds like you have custom block types called hero and content in your Portable Text schema, and you want to define how they render as JSX elements in your React components.

Here's how you can define custom block types as JSX elements using the @portabletext/react library:

import { PortableText } from '@portabletext/react'

// Define your custom components
const HeroComponent = ({ value }) => {
  return (
    <div className="hero">
      <h1>{value.title}</h1>
      <p>{value.description}</p>
      {/* Access other fields from your hero block */}
    </div>
  )
}

const ContentComponent = ({ value }) => {
  return (
    <section className="content-section">
      {/* Render whatever fields your content block has */}
      <div>{value.body}</div>
    </section>
  )
}

// Define the components object
const ptComponents = {
  types: {
    hero: HeroComponent,
    content: ContentComponent,
    // Add other custom block types here
  }
}

// Use it in your render
function MyPage({ portableTextData }) {
  return (
    <PortableText 
      value={portableTextData}
      components={ptComponents}
    />
  )
}

The key points from the Portable Text documentation:

  1. Custom block components receive a value prop (not node - that's the old API) containing all the data from your block
  2. Define them in the types object within the components prop
  3. Return JSX directly from your component functions

If you're getting an "Unknown block type" error, make sure:

  • The type names in your components.types object match exactly what you defined in your Sanity schema
  • You've included all custom block types that appear in your content

You can also check out this comprehensive guide on customizing Portable Text which covers the full flow from schema definition to React rendering.

What do your components look like so far?
  const components = {
    types: {
      hero: {
        home: <Main />
      }
    }
  }
return (
 <PortableText  components={components} value={homepage} />
)
I get as an error : Unknown block type "hero.home", specify a component for it in the
components.types
prop
I don't know how to define "hero.home" as a type
homepage
contains all the fields in the screenshot
Got it. What does the schema for that look like?
/schemas/documents/homepage.ts

 defineField({
      name: 'hero',
      title: 'Hero',
      type: 'hero.home',
      group: 'editorial',
    }),

/schemas/objects/hero/home.ts

export default defineField({
  name: 'hero.home',
  title: 'Home hero',
  type: 'object',
  fields: [
    // Title
    defineField({
      // name: 'title',
      // title: 'Title',
      // type: 'text',
      // rows: 3,
      name: 'titleBlock',
      title: 'Title Block',
      type: 'array',
      of: [
        {
          type: 'block',
          marks: {
            decorators: [
              { title: 'Strong', value: 'strong' },
              { title: 'Emphasis', value: 'em' },
              { title: 'Code', value: 'code' },
              {
                title: 'Highlight',
                value: 'highlight',
                icon: HighlightIcon,
                component: HighlightDecorator
              }
            ]
          }
        }
      ]
    }),
    // Link
    defineField({
      name: 'links',
      title: 'Link',
      type: 'array',
      of: [{type: 'linkInternal'}, {type: 'linkExternal'}],
      validation: (Rule) => Rule.max(1),
    }),
    // Content
    defineField({
      name: 'content',
      title: 'Content',
      type: 'array',
      validation: (Rule) => Rule.max(1),
      of: [
        {
          name: 'productWithVariant',
          title: 'Product with variant',
          type: 'productWithVariant',
        },
        {
          name: 'imageWithProductHotspots',
          title: 'Image',
          type: 'imageWithProductHotspots',
        },
      ],
    }),
  ],
})

Is that
hero.home
object inside of a parent Portable Text array?
yes, if you see the
_type
of hero is
hero.home
Sorry, I mean have you put that entire
hero.home
block inside of another Portable Text array? I’m trying to figure out why it would be trying to serialize the container.
I am not sure I did understand your question 😞Though, if I let the
components
in PortableText empty and pass that query in the screenshot as
value
.This is what I receive eventually :

Unknown block type "home", specify a component for it in the `components.types` prop``
Thiss is the value I am passing
Is there a way to define these types
hero, modules, seo
in one portable text
yes
{
 title: "Portable Text Field",
 name: "article",
 type: "array",
 of: [
    {type: "block"}, 
    {type: "hero"}, 
    {type: "modules"}, 
    {type: "seo"}
  ],
},
this will create an insert tab in your portable text wysiwyg interface with all those components.
this is how your suppose to handle that. then in your portable text client component youd create a serializer for each component.
Would it impossible to achieve something similar without adding these components in the block editor?
to achieve the exact same thing youd probably have to make an array with each component including a component with a portable text field. that way you can add in components or text fields and order them as if it were using one portable text field.
Can you please give me an example if that possible 😄
     {
      title: "Components",
      name: "components",
      type: "array",
      of: [
        {
          type: "reference",
          to: {type: "article"},
        },
        {
          type: "reference",
          to: {type: "hero"},
        },
        .... etc
      ],
    },
this way you can add more of each item and arrange them in any order. which is essentially the exact same thing a portable text field would do when you insert a new document or object type.
Oooh, so I can use PortableText even if the schema doesn't necessarily have to be
block
as a field type?
youd create a new document type or object type where one field is
block
to achieve this. call that
article
which is the first entry in that example above.
Oh I understand! thank you so much!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?