rich-text icon indicating copy to clipboard operation
rich-text copied to clipboard

Empty p tags is being generated

Open daydream05 opened this issue 6 years ago • 18 comments

I read that rich text would remove the unnecessary empty <p></p> tags generated from the text editor. But for some reason, I'm still getting p tags.

Here's what my sample code looks like

const options = {
  renderNode: {
    [BLOCKS.HEADING_1]: (node, children) => <h1>{children}</h1>,
    [BLOCKS.HEADING_5]: (node, children) => <h5>{children}</h5>,
    [BLOCKS.EMBEDDED_ASSET]: (node) => {
      const fileUrl = node.data.target.fields.file['en-US'].url

      return (
        <ContentfulFixedAsset
           fileUrl={fileUrl}
        />
      )
    }
  }
}

documentToReactComponents(richText, options)

What am i doing wrong?

daydream05 avatar Jun 20 '19 21:06 daydream05

Contentful Rich Text Editor adds a trailing paragraph to a document. None of the renderers removes empty paragraphs from the document.

sbezludny avatar Jun 21 '19 11:06 sbezludny

@sbezludny - Is that the intended functionality of the Contentful RTE? If so, do you happen to know the rationale behind doing so?

CliffAw avatar Aug 07 '19 11:08 CliffAw

seeing this as well. It should be a bug. It makes me nervous to remove the last "p" on render.

coreysyms avatar Nov 11 '19 16:11 coreysyms

Has anyone been able to solve this issue?

blessanm86 avatar Nov 14 '19 13:11 blessanm86

This is a temp work around that im using right now. I parse the rich text data before i send to the component

function stripTrailingParagraphNodes(richtext) {
  let shouldStop = false;
  const reversedContent = [...richtext.json.content].reverse();

  richtext.json.content = reversedContent
    .filter(node => {
      if (!shouldStop) {
        if (node.nodeType === "paragraph") {
          const [{ value }] = node.content;
          if (value.trim()) {
            shouldStop = true;
            return true;
          }
          return false;
        } else {
          shouldStop = true;
          return true;
        }
      }
      return true;
    })
    .reverse();

  return richtext;
}

export default function RichTextRenderer({ richText }) {
  if (!richText) return null;

  let processedRichText = richText;

  try {
    processedRichText = stripTrailingParagraphNodes(richText);
  } catch (e) {}

  return documentToReactComponents(processedRichText.json, rendererOptions);
}

blessanm86 avatar Nov 14 '19 14:11 blessanm86

Honestly the easiest work-around is CSS, and what I use is simple. CSS: p:empty { display: none; } Any paragraph tag that is empty, hide it. You can use this universally like the above. Or more specifically wrap your displayed Contentful richtext entries in a div classed as such.

.richtext > p:empty { display:none; }

This can be problematic for clients who like to add vertical space with p tags but it's better than having my layout wrecked by either the content editor or the CMS.

This is a bit of a nuisance problem, so I understand why it's not high on the priorities, hope the above workaround helps!

coreysyms avatar Nov 14 '19 14:11 coreysyms

@coreysyms that's what I was doing all this time but then I changed my layout a bit to use display:grid and row-gap to add spacing between the paragraphs and then things broke.

blessanm86 avatar Nov 14 '19 15:11 blessanm86

We have the same issue, and it causes an extra unexpected (and unwanted) padding in our case ! Thanks @coreysyms for the css fix

waelhasan avatar Jul 16 '20 12:07 waelhasan

Wow I should have googled it first, thanks @coreysyms !

Just spent 30 minutes writing a recursive function to remove the empty objects from the content array where 1 line of css was enough.

franknoel avatar Jul 22 '20 03:07 franknoel

Hi This option for Paragraph worked for me:

[BLOCKS.PARAGRAPH]: (node, children) => (children != '') ? <p>{children}</p> : '',

dzinemon avatar May 06 '21 14:05 dzinemon

I am able to solve it with this check. Hope it will be helpful for the next poor soul.

    renderNode: {
      [BLOCKS.PARAGRAPH]: (node, children) => {
        return (children.length === 1 && children[0][1] !== '') || children.length > 1 ? <p>
            {children}
          </p> : null;
      },
}

I suggest it must be fixed by the library as contentful richtext is adding extra text or paragraph nodes. Cheers!

manirikhi avatar Jul 13 '21 02:07 manirikhi

I got it working (in TypeScript) using this:

[BLOCKS.PARAGRAPH]: (node, children) => {
  const isEmptyChildren = children?.toString().trim() === ''

  if (isEmptyChildren) return null

  return <p>{children}</p>
},

MatheusRich avatar Nov 11 '21 14:11 MatheusRich

Wondering how this has not been fixed with the issue being open since 2019

Justbigmack avatar Jan 27 '22 13:01 Justbigmack

I would love a built in answer for this.

hellonathanchung avatar May 03 '22 19:05 hellonathanchung

@MatheusRich's solution is the only one that worked for me as the p:empty doesn't help if you have :last-child CSS selectors.

glennflanagan avatar Sep 01 '22 09:09 glennflanagan

Wondering about this issue as well.

mmason2-godaddy avatar Oct 28 '22 01:10 mmason2-godaddy

@glennflanagan if taking css approach, you can use .rich-text *:empty to target all empty elements. Or even use .rich-text p:nth-last-of-type(1) &:empty if you want to target the last paragraph

csergiuu avatar Feb 08 '23 10:02 csergiuu

For my purposes, I have been using this code.

[BLOCKS.PARAGRAPH]: (node, children) => {
  if(node && Array.isArray(node.content) && node.content.length === 1 && node.content[0].value?.trim() === ""){
    return null;
  }
  return <p>{children}</p>;
},

Note: I get an empty <span/> inside the <p/> tag, so the CSS p:empty will not work in my code.

empty p   span

Extra note: The :has CSS selector (along with the :empty selector) was promising, but it is not supported in Firefox. https://developer.mozilla.org/en-US/docs/Web/CSS/:has

p:has(> span:empty){
    margin-bottom: 0;
}
firefox vs chrome

dattu-ca avatar Sep 21 '23 17:09 dattu-ca