Custom list component for RichText unordered list

Hello, I have a Rich Text filed that only takes unordered lists. I would like to add an SVG icon next to each list item. I currently solve this with CSS like this:

ul {
  list-style: none;
  padding-left: 0;
}
li {
  &:before {
    content: '';
    display: inline-block;
    height: 20px;
    width: 20px;
    background-image: url('/list-check.png'); // Fallback PNG
    background-image: url('/list-check.svg');
    background-size: cover;
    background-repeat: no-repeat;
    margin-right: 0.5rem;
  }
}

but would prefer to instead being able to access each list item and render something like this

<ul>
  <li>
    <CheckIcon />
    <span>{listItem}</span>
  </li>
</ul>

Is this possible to do? Thanks!

Hello @jprzpam

Thanks for reaching out to us.

You can achieve what you're hoping to do by using the HTML serializer function. The HTML Serializer allows you to change the HTML output of any Rich Text component, including the list items.

Take a look at the documentation I linked to and let us know if you have any questions about this :slight_smile:

Did it like this:

const propsWithUniqueKey = function (props, key) {
  return Object.assign(props || {}, { key })
}

// -- HTML Serializer
// This function will be used to change the way the HTML is loaded
const htmlSerializer = function (type, element, content, children, key) {
  const props = {}

  switch (type) {
    case Elements.listItem: // Unordered List Item
      return (
        <li>
          <ListCheckIcon />
          {children}
        </li>
      )

    case Elements.list: // Unordered List
      return React.createElement('ul', propsWithUniqueKey(props, key), children)

    default:
  }
}
export default htmlSerializer

And use it like this:

<RichText render={courseInfo.items} htmlSerializer={htmlSerializer} />

But how could I do so I can switch the kind of Icon rendered depending on some prop on the RichText? In my current solution I would always display the same icon for all list items. Thanks!

Hi @jprzpam. @Priyanka asked me to help out with this.

I'm happy that you got the HTML Serializer working on your project. If you're looking to have control over the icon that is displayed, then (as you've found) this becomes more complicated. This level of customization isn't really possible with the Rich Text field.

What I suggest is to create a custom Slice for your lists. Do you currently use Slices to build your pages? If not, then I highly suggest that you convert your pages to use Slices. They allow you to mix and match custom components to build your pages. You can read more about slices in our documentation:

Slices would allow you to create a custom component for your lists. You could model the list slice in a number of ways. One example would be to put an Image field and a Rich Text field in the repeatable zone of the Slice. This would allow you to use the Image field for the icon and the Rich Text for the list item text.

Let us know if you have any questions about this :slight_smile:

Hi Levi, I do use slices and understand the solution you propose but it honestly does not fit my needs as it will become tedious for users adding list content. It will take much longer to keep adding item by item. I think I will stay with using CSS for adding the list icon.

It would be nice to be able to have that level of customization with Rich Text field but I understand it might be difficult or simply out of scope for you right now.

Thank you! :slightly_smiling_face:

Hello @jprzpam

I understand it could be tedious for you, although it's the best way. If you are going with using CSS, I have one suggestion for you. You have an option of adding labels for the list items in Prismic. These labels will be available on the front end as class names for span inside list items. You can write CSS accordingly.
Learn more about Custom labels in the Rich Text configuration article.

I hope it solves your issue. Let me know if you have any further questions.

Thanks,
Priyanka

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.