How to pass className and access custom listItems in @portabletext/react?

8 replies
Last updated: Dec 1, 2025
Upgraded to the new
@portabletext/react
. Is a reason I can't seem to pass in
className
:
Like this:

const ptComponents = {
  list: {
    bullet: ({ children, className }) => {
      return <ul className={className}>{children}</ul>;
    },
  },

<PortableText className={className} ... components={ptComponents} />
Alternately, I'm not sure how to access custom
listItems
. Where do I designate which
listItem
is used for a list? Do I have to bake that into the Sanity schema? If so, how?
AI Update

The className prop on the root <PortableText> component does not automatically propagate to your custom list components. This is just how the library works—it doesn't pass arbitrary props down to your serializers.

Passing className to Lists

You have two main options:

Option 1: Wrap the PortableText component

<div className={className}>
  <PortableText value={content} components={ptComponents} />
</div>

Option 2: Define className directly in your custom components

const ptComponents = {
  list: {
    bullet: ({ children }) => {
      return <ul className="my-custom-bullet-list">{children}</ul>;
    },
    number: ({ children }) => {
      return <ol className="my-custom-numbered-list">{children}</ol>;
    }
  }
}

If you need dynamic styling, you can close over the className variable in your components definition, or create a function that returns the components object with your desired classes.

Accessing Custom List Items

For custom listItem components, you define them alongside your list components in the components object:

const ptComponents = {
  list: {
    bullet: ({ children }) => <ul className="bullet-list">{children}</ul>,
    number: ({ children }) => <ol className="numbered-list">{children}</ol>
  },
  listItem: {
    bullet: ({ children }) => <li className="bullet-item">{children}</li>,
    number: ({ children }) => <li className="numbered-item">{children}</li>
  }
}

The list type (bullet or number) is determined by the Portable Text content itself—when an editor creates a bulleted or numbered list in Sanity Studio, that information is stored in the Portable Text data. The @portabletext/react library automatically matches your custom bullet or number serializers based on what's in the content. You don't need to manually designate which listItem to use.

Custom List Types Beyond Bullet and Number

If you want to add custom list types beyond the standard bullet and number, you would need to customize your Portable Text schema in Sanity Studio. The guide on customizing Portable Text covers how to extend the schema with custom list styles, which you can then handle with matching serializers in your components object.

Show original thread
8 replies

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?