Issue with @sanity/block-content-to-react package and rendering Portable Text in Sanity not formatting correctly.

11 replies
Last updated: Mar 27, 2021
Hey everyone, first time posting here!
I followed the Sanity tutorial for making a blog with Sanity, React and Next:

https://www.sanity.io/blog/build-your-own-blog-with-sanity-and-next-js
This is my first time integrating Sanity into any project, so I basically stuck to the guide as is.

I'm having an issue with the @sanity/block-content-to-react package and rendering the Portable Text the way I format it in Sanity. (Some things come through, like bold and italics, but most things dont, like spacing, or new lines or any of the headers (H1, H2, etc).

Here's the link to my site:
https://ellies-lego-land.vercel.app/
Here's the link to my Github where I import <BlockContent />:
https://github.com/jamesncox/ellies-lego-land/blob/main/web/pages/post/%5Bslug%5D.js
I've read through the docs on block-content-to-react, but honestly, I'm having trouble making sense of it.

Thanks in advance for any help!
AI Update

I can help you with this! The issue you're experiencing is because @sanity/block-content-to-react is deprecated and has been replaced by the newer @portabletext/react library. The older package has some limitations and doesn't handle all Portable Text features as reliably as the modern replacement.

Looking at your code on GitHub, you're using the deprecated package, which is likely why headers, spacing, and line breaks aren't rendering properly while basic marks like bold and italics still work.

Here's how to fix it:

1. Install the new package:

npm install @portabletext/react

2. Update your imports in [slug].js:

// Replace this:
import BlockContent from "@sanity/block-content-to-react";

// With this:
import { PortableText } from "@portabletext/react";

3. Update how you render the content:

// Replace this:
<BlockContent
  blocks={body}
  projectId="your-project-id"
  dataset="production"
/>

// With this:
<PortableText value={body} />

The new library automatically handles all standard Portable Text elements (headings, paragraphs, lists, line breaks, etc.) out of the box without needing to pass projectId or dataset.

If you need custom styling:

You can pass custom components to control how different elements render:

const components = {
  block: {
    h1: ({children}) => <h1 className="text-4xl font-bold">{children}</h1>,
    h2: ({children}) => <h2 className="text-3xl font-bold">{children}</h2>,
    normal: ({children}) => <p className="my-4">{children}</p>,
  },
  marks: {
    link: ({value, children}) => <a href={value.href} className="text-blue-500">{children}</a>,
  }
}

<PortableText value={body} components={components} />

Key differences in the migration:

  • The prop name changed from blocks to value
  • The node prop in custom serializers is now called value
  • Components are organized under block, marks, list, and types categories

This should fix all your rendering issues on your Ellies Lego Land site! The @portabletext/react library properly handles spacing, line breaks, and all heading levels that the older package struggled with. Check out the ultimate guide for customizing Portable Text if you need more advanced customization options.

Hi and welcome, User! Do you have an example from one of your code blocks of code that isn’t serializing? For example, on this page , is there anything in that block of text that you’d expect to be formatted differently?
Hi, User, thanks!
The main thing I'm looking for is separate paragraphs persisting, so it doesn't come out as one big block of text. But would love to be able to use the built-in H1 etc styles (h2, h3, quotes, etc). I'll post some screen shots momentarily!
I could be wrong about the function of @sanity/block-content-to-react, but I had assumed it was to format the text to look similar to the way it's uploaded.
It looks like certain things are coming through (distinct p tags, for example). I don't see any h* tags on your deployed site, but the default serializer should handle them. I think the remaining work might just be in your CSS (it looks like the margin and padding on p elements might be "normalized").
user A
that's interesting, I didn't realize that my local styles were overriding the serializer. I'll try to update that component today and see if I can't get it working. Thanks!
The way I understand it, it’s slightly different than that. In Sanity, your rich text lives as portable text, which is a structured way of representing data. To present it on the web, it must be “converted” to a markup language (i.e., HTML), which is the task of the serializer. The serializer is basically parsing your portable text and following a set of instructions to convert to markup.
Once that’s done, you’ll end up with your content represented as HTML. However, it will be up to your styles on the front end to handle the presentation of that data. You’re using Tailwind for your CSS, which (I believe) will normalize your styles to give you a clean slate to work with. This block of CSS is removing margins from several elements, including paragraphs:


blockquote, dd, dl, figure, h1, h2, h3, h4, h5, h6, hr, p, pre {
 margin:0
}
This is strictly on your front end. You can style your elements in the Sanity studio but those styles will not be connected at all to your styles on the front end. For example, I could replace all my list bullets in the studio with unicorn heads and it would not impact my front end code at all. You’re seeing h1, h2, etc tags styled in the studio because there is an opinionated set of styles being applied, but those presentational decisions will not carry over to your front end. So it’s not so much that your front end styles are overriding your serializer, but rather that your front end styles appear to be getting normalized (because you’re using Tailwind on the front end) but then not being customized from there.
That does make sense. Thanks so much for your explanation and time helping me!
Any time!
(that's what I get for attempting to incorporate three new techs, next, sanity and tailwind, into my workflow all in the same project 🤣)
All good! I think those three are great to learn together.
I also love that you're building a Lego blog for your daughter. 👍

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?