Can I wrap multiple <li> elements in a div using Sanity portable text marks?
I understand what you're trying to do, but unfortunately Portable Text decorators (marks) can't wrap multiple list items (<li>) together because decorators work at the inline/span level, not at the block structure level.
When you apply a decorator like "div" to text within a list, it only wraps the text content inside the <li>, not the <li> elements themselves. This is by design—marks are meant for inline formatting (like bold, italic, links), not for changing block-level structure.
What You Can Do Instead
Here are a few approaches to achieve what you want:
1. Use Custom List Rendering
You can customize how lists are rendered using @portabletext/react serializers:
const components = {
list: {
bullet: ({children}) => (
<ul>
<div className="wrapper">
{children}
</div>
</ul>
)
}
}
<PortableText value={content} components={components} />However, this wraps all list items in that list, not just specific ones.
2. Create a Custom Block Type
Instead of using the built-in list feature, create a custom block type in your schema:
{
name: 'wrappedList',
type: 'object',
fields: [
{
name: 'items',
type: 'array',
of: [{type: 'block'}]
},
{
name: 'wrapInDiv',
type: 'boolean',
title: 'Wrap in div'
}
]
}Then render it with custom logic in your frontend to conditionally wrap specific items based on your needs.
3. Use CSS Instead
If this is purely for styling purposes, you might be able to achieve the visual effect with CSS using pseudo-elements, CSS Grid, or Flexbox on the <ul> without changing the HTML structure.
4. Custom listItem Serializer
You could also add logic to the listItem serializer to detect certain conditions and wrap accordingly, though this gets complex:
const components = {
listItem: ({children, value, index}) => {
// Custom logic to determine if this should be wrapped
return <li>{children}</li>
}
}The key limitation is that marks/decorators operate on text spans, not block structures, so they can't restructure your list hierarchy. You'll need to either customize the list rendering as a whole or create a custom block type for more complex list structures where you need selective wrapping.
Show original thread25 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.