Issue with serializer not applying styles to list items

15 replies
Last updated: Apr 14, 2020
Hello, I'm trying to add some styles to my list items, but my serializer is not working. Not sure why, any one spot the error? My serializer:

listItem: props => {
  switch (props.node.listItem) {
    case "bullet": {
      return <ul className="liststyle">{props.children}</ul>
    }
    case "number": {
      return <ol>{props.children}</ol>
    }
    default: {
      return <li>{props.children}</li>
    }
  }
},
Full serializer at
https://gist.github.com/AndreasJacobsen/de9a9eb192c8face517f9fd21313f974 , right now I'm trying to add the classname liststyle to a all ul elements in a block content component
AI Update

I can spot the issue! In @sanity/block-content-to-react, you're using the wrong serializer key. You're defining listItem when you should be using list instead.

The listItem serializer handles individual <li> elements, but the list serializer handles the wrapping <ul> and <ol> elements. Here's the corrected version:

list: props => {
  switch (props.type) {
    case "bullet": {
      return <ul className="liststyle">{props.children}</ul>
    }
    case "number": {
      return <ol>{props.children}</ol>
    }
    default: {
      return <ul>{props.children}</ul>
    }
  }
},
listItem: props => <li>{props.children}</li>

Notice two key changes:

  1. Changed listItem to list for the wrapper elements
  2. Changed props.node.listItem to props.type - the list type is accessed via props.type, not props.node.listItem

The list serializer receives props.type which will be either "bullet" or "number", and props.children which contains all the rendered list items. The listItem serializer then handles how each individual <li> is rendered.

Side note: The @sanity/block-content-to-react package is deprecated. For new projects, you should use @portabletext/react instead, where the API is slightly different (uses components instead of serializers and value instead of node).

Hi Andreas, does it work without the class? The code looks correct to me but you could try defining the components separately and replacing
<ul className="liststyle">{props.children}</ul>
with something like
<UlItem>{props.children}</UlItem>
. Perhaps it doesn’t like the quotation marks in the current approach, although that shouldn’t matter.
I'm getting "ULItem is not defined", so it seems to be ish working, but I cannot get the className, it's just an empty className
if I change it to say blockquote it stays as a ul without a css class, so the serializer is not hitting my bullet point list. Even thoug the graphQl tells me this is of type bullet
My sanity blockContent file has the following for lists

lists: [
        
{ title: 'Bullet', value: 'bullet' },
        
{ title: 'Numbered', value: 'numbered' },
      
],
The GraphQL output and
blockContent
content for lists look OK to me. Does it work if you remove all other serializers and just leave the
listItem
one?
does not work with only listItems either
Just to check a silly little thing: if you change
<ul className="liststyle">{props.children}</ul>
to
<p>{props.children}</p>
, are you seeing any change?
no, not seing any change at all
I'm calling it like this

<StatementBlock
  blocks={data.sanityAccessibilityStatement._rawStatement}
/>
with an import of course

import StatementBlock from "../components/Sanity/blockContent"

Hmm I’m having a hunch. I think you’re missing a list renderer. Here’s a basic example just to confirm it’s doing something:
const ListRenderer = ({ children }) => {
  return <ul>{children}</ul>;
};
const ListItemRenderer = ({ children }) => {
  return <li>{children}</li>;
};
const serializers = {
  ...,
  list: ListRenderer,
  listItem: ListItemRenderer,
  ...
}
Still the same error, I updated the gist with the code you so generously provided https://gist.github.com/AndreasJacobsen/de9a9eb192c8face517f9fd21313f974
but I also want to support numbered lists (edit, I can just make a switch case inside the listRender I realized)
Edit2: I updated the gist to contain more files, I just don't understand why this is not working. feel free to reply tomorrow instead though!
Just tested the above code locally and can confirm it’s working, also with a class name on the
ul
element. Are the other serializers working for you?
no, I updated the gist to also include the file where I'm using the blockContent compontent, I can add/remove classnames the titles and the other elements defined over listItem
Nasty 🤓 It doesn’t give any errors because the missing bracket is added at the end, but it’s enough to make it all fail. There’s one closing bracket missing to close off
types
and there’s one extra bracket at the very end of
serializers
if you do close off
types
before.
Try this:

const serializers = {
  types: {
    block(props) {
      switch (props.node.style) {
        case "h1":
          return <h1 className="title is-1 introTitle">{props.children}</h1>
        case "h2":
          return <h2 className="title is-2 introTitle">{props.children}</h2>
        case "h3":
          return <h3 className="title is-3 introTitle">{props.children}</h3>
        case "h4":
          return <h4 className="title is-4 introTitle">{props.children}</h4>
        case "blockquote":
          return <blockquote>{props.children}</blockquote>
        default:
          return <p>{props.children}</p>
      }
    }
  },
  list: ListRenderer,
  listItem: ListItemRenderer,
  figure(props) {
    return <Figure image={props.node} />
  },
  marks: {
    internalLink: ({ mark, children }) => {
      const { slug = {} } = mark
      const href = `/${slug.current}`
      return <Link to={href}>{children}</Link>
    },
    externalLink: ({ mark, children }) => {
      const { blank, href } = mark
      return blank ? (
        <a href={href} target="_blank" rel="noopener noreferrer">
          {children}
        </a>
      ) : (
        <a href={href}>{children}</a>
      )
    }
  }
}
It works :party_parrot: :party_parrot: :party_parrot: :party_parrot:Thank you Peter, you are amazing
I may have over estimated my switch case abilities, do you know how I can write a switch case for the list items?

const ListRenderer = ({ children }) => {
  
switch (children.props.node.listItem) {
    
case "bullet":
      
return <ul _className_="liststyle">{children}</ul>
    
default:
      
return (
        
<ol>
          
{children}
         
</ol>
      
)
  
}

}
WIth this all items are returned as &lt;ol&gt; lists (default), even the ones that are supposed to be unordered lists
Edit: using children.props.node.listItem I get an error stating "Cannot read property 'node' of underfined

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?