Joint session with Vercel: How to build intelligent storefronts (May 15th)

PortableText 'Li' JSX component type error fix

33 repliesLast updated: Nov 30, 2025

How do I fix this in PortableText?
Type error: 'Li' cannot be used as a JSX component.
   Its element type 'ReactElement<any, any> | Component<PortableTextComponentProps<PortableTextListItemBlock<PortableTextMarkDefinition, PortableTextSpan, string, string>>, any, any>' is not a valid JSX element.
AI Update

This TypeScript error occurs when defining custom list item components in @portabletext/react due to type incompatibility between what TypeScript expects for a JSX component and what you're providing.

The issue typically happens when you define a listItem component in your components object. The error message indicates that TypeScript sees the Li component type as ReactElement | Component, which isn't a valid JSX element type signature.

The Solution:

Make sure your listItem component is defined as a proper functional component that returns JSX, not as a class component or mixed type. Here's the correct way to type it:

import { PortableText, PortableTextComponents } from '@portabletext/react'

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

// Then use it:
<PortableText value={portableTextContent} components={components} />

Key Points:

If you're using custom types:

import type { PortableTextComponents, PortableTextListItemBlock } from '@portabletext/react'

const components: PortableTextComponents = {
  listItem: ({children, value}) => {
    // value gives you access to the full block data if needed
    return <li>{children}</li>
  }
}

The error usually resolves when you ensure your component definitions are consistently typed as functional components. Avoid mixing class components, or returning conditional types that might be ReactElement in some cases and Component in others. Keep them as simple functional components that always return JSX.

For more details on customizing Portable Text rendering, check out the guide on customizing Portable Text from schema to React component.

Show original thread
33 replies

Was this answer helpful?

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.

Related contributions