How to render decorator highlighting styles in React frontend?

5 replies
Last updated: Apr 5, 2021
I have made a decorator for highlighting text. As you can see in the image below, in the editor, the highlighted text has yellow background color. However, I don't see the yellow highlighting in my React frontend. What am I missing?
AI Update

The issue is that creating a custom decorator in Sanity Studio only adds the visual styling in the editor itself - it doesn't automatically render that styling on your frontend. You need to explicitly tell your React frontend how to render that custom decorator.

When you create a decorator (like highlighting), Sanity stores it as a "mark" in the Portable Text data. To display it with the yellow background on your frontend, you need to add a custom serializer/component for that mark.

If you're using the modern @portabletext/react library:

import { PortableText } from '@portabletext/react'

const components = {
  marks: {
    highlight: ({children}) => (
      <span style={{backgroundColor: 'yellow'}}>{children}</span>
    ),
  },
}

// In your component
<PortableText value={yourContent} components={components} />

If you're using the older @sanity/block-content-to-react library:

import BlockContent from '@sanity/block-content-to-react'

const serializers = {
  marks: {
    highlight: ({children}) => (
      <span style={{backgroundColor: 'yellow'}}>{children}</span>
    ),
  },
}

// In your component
<BlockContent blocks={yourContent} serializers={serializers} />

The key is that the mark name in your serializer (highlight in the examples above) must match the value you specified when defining the decorator in your Sanity schema.

If you're using the older library, note that @sanity/block-content-to-react is deprecated and you should migrate to @portabletext/react for new projects. The main difference is that the new library uses a components prop instead of serializers, and accesses node data through value instead of node.

Show original thread
5 replies
Have you created a serializer for this decorator? https://www.sanity.io/docs/portable-text-to-react#rendering-custom-marks
I went through the links. However, I am not sure how do I implement a serializer for highlighting text. In the OnePost.js component (the component for rendering one single blog post) I have already a serializer for code block. So, how do I add another serializer for highlighting text and how would that serializer look? Pls. help.

OnePost.js
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import sanityClient from "../client.js";
import BlockContent from "@sanity/block-content-to-react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { coldarkDark } from "react-syntax-highlighter/dist/esm/styles/prism";

export default function OnePost() {
  const [postData, setPostData] = useState(null);
  const { slug } = useParams();

  const serializers = {
    types: {
      code: (props) => (
        <SyntaxHighlighter
          language={props.node.language}
          style={coldarkDark}
          showLineNumbers
          lineNumberStyle={{
            padding: "0 5px 0 0",
            fontSize: 14,
            borderRight: "1.5px solid darkgray",
            marginRight: "10px",
          }}
        >
          {props.node.code}
        </SyntaxHighlighter>
      ),
    },
  };

  useEffect(() => {
    sanityClient
      .fetch(
        `*[slug.current == $slug]{
          title,
          slug,
          mainImage{
            asset->{
              _id,
              url
             }
           },
         body,
        "name": author->name,
        "authorImage": author->image
       }`,
        { slug }
      )
      .then((data) => setPostData(data[0]))
      .catch(console.error);
  }, [slug]);

  if (!postData) return <div>Loading...</div>;

  return (
    <div className="col-sm-10 col-md-6 mx-auto mt-5">
      <div>
        <h1 className="font-weight-bold">{postData.title}</h1>
        <div>
          <h6 className="text-secondary">{postData.name}</h6>
        </div>
      </div>
      <div className="text-muted">
        <BlockContent
          blocks={postData.body}
          projectId={sanityClient.projectId}
          dataset={sanityClient.dataset}
          serializers={serializers}
        />
      </div>
    </div>
  );
}
Hi Hemant. In your serializers object (
const serializers = { … }
), you’ll notice a
types
object (where you defined
code
). That’s where you would define serializers for block types. Since highlighted text is a mark (a text child of a block—think inline elements), you want to add
marks
as a sibling of
types
and set up your serializer. Something like:

const serializers = {
  types: {
    code: (props) => ( ... ),
  },
  marks: {
    highlight: ({ children }) => (
      <span style={{ backgroundColor: 'yellow' }}>{children}</span>
    ),
  },
};
Thanks, Problem solved.

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?