How to globally configure serializers for @sanity/block-content-to-react?

11 replies
Last updated: Aug 18, 2022
Hello everyone, I'm trying to add the ability to embed youtube videos into my block content, following this tutorial: https://www.sanity.io/guides/portable-text-how-to-add-a-custom-youtube-embed-block
I've set up my schema properly, but I have a question regarding the front-end implementation (
@sanity/block-content-to-react
).

Here , the docs say: "where you want to be able to output this YouTube embed, do the following" - My question is, is there a way to set this up such that I don't need to implement this block of code within every document type that I wish to have the ability to embed videos into? Ideally, this "serialization" would be done at a higher level such that my <BlockContent> widget would look something like this:
<BlockContent blocks={mySchemaType.body} />
, rather than
<BlockContent blocks={mySchemaType.body} serializers={serializers} />

It seems counter-intuitive to have to add this block of code + serializer prop to every single iteration of &lt;BlockContent/&gt; in my project... Maybe I'm not understanding this correctly?
AI Update

You're asking a great question that many developers encounter when working with Portable Text! The good news is that you absolutely can avoid repeating the serializers configuration everywhere.

First, a quick note: the tutorial you're following uses @sanity/block-content-to-react, which is now deprecated. You should use @portabletext/react instead, which is the modern, officially supported library. The API is similar but with some improvements (like using components instead of serializers, and value instead of node).

The Solution: Create a Reusable Component

The best approach is to create your own wrapper component that includes all your custom serializers/components by default. Here's how:

// components/PortableTextRenderer.jsx
import { PortableText } from '@portabletext/react'
import YouTubeEmbed from './YouTubeEmbed'

// Define your components once
const ptComponents = {
  types: {
    youtube: ({ value }) => <YouTubeEmbed url={value.url} />,
    // Add other custom types here
  },
  marks: {
    // Custom marks if needed
  },
  // Other customizations
}

// Create your reusable component
export default function PortableTextRenderer({ value }) {
  return <PortableText value={value} components={ptComponents} />
}

Now throughout your app, you can simply use:

<PortableTextRenderer value={mySchemaType.body} />

This gives you a single place to manage all your Portable Text rendering logic. If you need to add support for another embed type or custom block, you just update this one component.

When You Need Flexibility

If you occasionally need to override or extend the default components for specific use cases, you can make your wrapper more flexible:

export default function PortableTextRenderer({ value, components = {} }) {
  // Merge custom components with defaults
  const mergedComponents = {
    types: { ...ptComponents.types, ...components.types },
    marks: { ...ptComponents.marks, ...components.marks },
    // ... merge other categories
  }
  
  return <PortableText value={value} components={mergedComponents} />
}

This pattern is exactly what you're looking forβ€”it centralizes your configuration while keeping things DRY (Don't Repeat Yourself). The Portable Text documentation covers more advanced customization patterns if you need them.

Remember to migrate to @portabletext/react when you can, as it has better TypeScript support and is actively maintained!

Show original thread
11 replies
Perhaps this isn't the Reactiest thing to do but could you make a component that contains that inside and just always has a default serializers value wherever it goes? Like &lt;AndrewBlockContent&gt; and inside it's just defining the serializers and loading them into the real BlockContent?
I only have videos on certain document types so I just assumed it was there to have less code/maintenance for something where it's irrelevant, but if you're re-using the block
editor instance (which is a good idea for many reasons, including attribute count) that totally makes sense to fix it as a default.
I have a tiny site that I staggered through making the Studio for initially so I have three or four different kinds and treat them differently (they ought to be the same but time+energy
πŸ˜ƒ
^^ that's what we do. The portableText components and serializers are saved in a single file that we import into a component. In our case, this is all handled in a template component.
yeah... I was thinking of doing something like this but wondered if there was a more Sanity-geared solution. It's kinda hacky, but I'm sure it'll work. I'll give this a shot, just a bit of a pain to have to replace every &lt;BlockContent&gt; with my own custom serialized blockcontent component
what do you mean by attribute count btw?
Sanity is data only. The presentation layer is decoupled by design. The way you present the block information, in this case the youtube embed, is always determined on the front end. So, it's not really hacky since your intention is to use the front end package to display the content in a specific manner on the front end.
Most IDEs like Visual Studio Code have a handy find and replace if you kept the naming convention similar, and it probably could catch the imports as well.
It's a one-off nesting versus all the extra work to keep adding things redundantly. If it's hacky at least it's simple-hacky
πŸ˜ƒ
Attribute count in Sanity is a limitation placed on your dataset as implemented where all the various combinations of types of docs and the fields they can have are capped:
https://www.sanity.io/docs/attribute-limit -- I highly recommend giving that a five to ten minute read because it's full of useful clarity.
gotcha! the custom serialized markdown component works btw, I think I'll just end up using this as a solution. Thanks yall :)
Thanks Vincent, I'll give that a read right now!
Very welcome,
user C
I have been here about six months and only even heard of someone running into it twice, so it's not exactly easy to hit, but if it helps you understand and plan, then yay πŸ˜ƒ
Always good to know what you might run into regardless! I appreciate the heads-up πŸ™‚
Chiming in to remind you that
@sanity/block-content-to-react
is deprecated. You should migrate to https://github.com/portabletext/react-portabletext . It should be relatively easy though.

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?