Removing p Tags from Contentful List Items

Hero image for Removing p Tags from Contentful List Items. Image by Paweł Czerwiński.
Hero image for 'Removing p Tags from Contentful List Items.' Image by Paweł Czerwiński.

The combination of Gatsby and Contentful together makes for a very powerful development toolset: a very fast, static, website built on top of a modern and futureproof(ish) framework, with content management that a client can easily understand and familiarise themselves with.

I've written about some of the more nuanced issues that can arise when integrating with Contentful before, but today I'd like to share one of my personal pet peeves: superfluous elements and nonstandard markup structure.

Specifically: the way that Contentful likes to wrap the content of list items, inside of a <p>, resulting in generated markup that looks like this:

<ul>  <li>    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>  </li>  <li>    <p>Nulla viverra est vel cursus facilisis.</p>  </li>  <li>    <p>Nam a tempor dolor, commodo sodales felis.</p>  </li></ul>

Yuck.

I feel that this likely relates back to something I've said before about Contentful: they provide rich content as an object, where each node roughly correlates to a blocklevel element (e.g., a <p>), so more often than not, items which you would generally expect to be blocklevel themselves (e.g., an <li>) are not.

Fortunately, they do provide LIST_ITEM as a BLOCK type within @contentful/richtexttypes, which at least means we can target list items specifically when it comes to rendering them.

Sergio Pellegrini on the GitHub issue provides the answer, which I have modified a little here:

[BLOCKS.LIST_ITEM]: (node, children) => {  const transformedChildren = documentToReactComponents(node, {    renderMark: options.renderMark,    renderNode: {      [BLOCKS.PARAGRAPH]: (node, children) => children,      [BLOCKS.LIST_ITEM]: (node, children) => children,    },  });  return <li>{transformedChildren}</li>;}

Fundamentally what this is doing is within renderNode, where we come across a LIST_ITEM, it transforms the children by passing them back through documentToReactComponents(). Where it finds a child of type PARAGRAPH, it returns the children of that, without any wrapping markup.

Where I've edited this compared to the original solution on GitHub is to also option renderMark, which points back to the original options variable. This means that any marks that appear within the list item (inline items: bold, underline, inline code, etc) will still get rendered as I've defined. If you have not defined any special handling of marks, you should omit this line.


Categories:

  1. CMS
  2. Contentful
  3. Cross‑Browser Compatibility
  4. Development
  5. Front‑End Development
  6. Gatsby
  7. Guides
  8. JavaScript
  9. Next.js
  10. React