Can I wrap multiple <li> elements in a div using Sanity portable text marks?

25 replies
Last updated: Jan 28, 2026
hi ! i'd like to know if i can wrap my
<li>
elements in a div.current schema :
marks: {

decorators: [

{ title: "strong", value: "strong" },

{ title: "em", value: "em" },

{ title: "strike", value: "strike" },

{ title: "underline", value: "underline" },

{ title: "blue", value: "blue" },

{ title: "green", value: "green" },

{ title: "animation", value: "animation" },

{ title: "muted", value: "muted" },

{ title: "div", value: "div" },
But when i do something like that it just wrap my element in the li not the 2 li elements i want.
I just want the last li elements to be wrapped inside the div
AI Update

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 thread
25 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?