How to best deal with HTML content returned that should be parsed as plain text?

I am writing some stuff for my component. I am grabbing the excerpt from and trying to render it in a paragraph element.

I know of a couple of ways to do this but none of them are sufficient to my needs and I’m curious if other people have suggestions.

First there is the use of dangerouslySetInnerHTML. The problem with this is that it creates a <div> with the <p> tag inside it and I don’t want this. It’s clunky and adds unnecessary nodes to the DOM tree. I need a better solution.

Second, there is the html2react component included with frontity.

html2react is a solid component, and it parses and returns correctly a single <p> element containing the sanitized text. However there are two things I don’t like about using it.

  1. I can’t add a className=excerpt to the component like I’d like. Maybe your response is “why do you want to do this” and let’s just say “I do because that’s how I like to work”. I like having easy to access CSS classes even when using Styled Components etc.
  2. I’d prefer to use a more semantic component name than <html2React html={item.excerpt.rendered}>. I could just import the component under a different name but the fact remains that I’m using a component to perform imperative operations and that doesn’t sit right with me. Maybe this is just aesthetics on my part, or style or something, but I would prefer to have a clearer demarcation between mark up and processing of the content of markup.

Maybe neither of these reasons make sense to you. That’s fine. If nothing else I’m asking this question to better understand frontity and to push myself to understand React better and how and why things are built the way they are.

The last solution I’ve considered doesn’t work. I had a tutoring session today with a mentor and we were going over the different ways that content can be fetched and then inserted into the DOM. They used element.textContent to insert some text content into an element. That seemed like what I wanted to do so I tried the same thing as follows:

<p key={item.index} className="excerpt">
            {item.excerpt.textContent}
          </p>

And this does not work. I don’t know why. I’d be curious if someone could tell me. It does properly produce a <p> tag but it doesn’t actually return the content.

I’m wondering if perhaps this is something specific to react or perhaps it’s something specific to frontity?

Any clues would be super appreciated. I hope my question and thinking is clear. I know that perhaps some of what I’m wanting to do differs from the way other people are used to doing things, but even if I end up just adopting the methods already used by others, I want to know why the methods I instinctively prefer won’t work. This project is primarily meant as a means to learn :slight_smile:

Hi I don’t want to bother anyone but I was just going through the newsletter release notes and saw that “decode” had been added: https://docs.frontity.org/api-reference-1/frontity#decode

Would decode help in solving this issue I’m facing? Am I understanding the issue correctly?

There was no feature thread but I read the docs and it seems like it’s a function that processes text containing HTML and returns the raw text results, which sounds like what I want, but I wasn’t sure.

You can add a top div with the class name:

const excerpt = `<div class="excerpt">${item.excerpt.rendered}</div>`;

then pass it down to either Html2React or dangerouslySetInnerHTML .

And you can name html2React whatever he wants when by assigning it to a variable:

const Html = libraries.html2react.Component;

No, decode is just an entity decoder. Sorry for the lack of description in the documentation. I have just fixed that.

1 Like

I wanted to keep things more semantic in their presentation, so I ended up just renaming it const Excerpt = libraries.html2react.Component;

but I’m more interested in learning why the item.excerpt.textContent doesn’t work?

It’s textContent a standard vanilla Javascript function?

actually I just tried adding on the class=“excerpt” solution and it’s not rendering out anything.

Here’s the full component file

import React from "react";
import { connect, styled } from "frontity";
import Link from "../Link";
import FeaturedMedia from "../FeaturedMedia";
import { dateFromItem } from "../../utilities";

const ArchiveItem = ({ state, item, libraries }) => {
  const excerptHTML = `<div class="excerpt">${item.excerpt.rendered}</div>`;
  const Excerpt = libraries.html2react.Component;
  const Date = libraries.html2react.Component;
  return (
    <section className="post-link">
      <Link link={item.link}>
        <Title dangerouslySetInnerHTML={{ __html: item.title.rendered }} />

        {/* //TODO: This seems like it should be separated into a separate component */}
        {state.theme.isBlog && <p className="date">{dateFromItem(item)}</p>}

        <FeaturedMedia id={item.featured_media} />

        {/* //TODO: This too  */}
        {state.theme.isBlog && item.excerpt && (
          <Excerpt html={excerptHTML} />
          // <Excerpt key={item.index} className="excerpt">
          //   {item.excerpt.textContent}
          // </Excerpt>
        )}
      </Link>
    </section>
  );
};

export default connect(ArchiveItem);

//-  𝗖𝗦𝗦
const Title = styled.h1`
  font-size: 4rem;
  position: relative;
  display: inline;
  z-index: 10;
  font-weight: 700;
  color: black;
  margin: 0;
  padding-top: 24px;
  /* margin-bottom: -40px; */
  padding: 25px 25px 0 25px;
  box-sizing: border-box;
  vertical-align: bottom;
`;

const Excerpt = styled.p`
  color: black;
`;


Actually the way I think I might solve this is by pulling the date and excerpt into their own components. That way I don’t have the ternary logic junking up the mark up and I think that will actually allow me to add the classes via the lower level component.

As far as I know node.textContent doesn’t work with React, as React doesn’t have any nodes. Apart from that, they have an official way, written in their docs, to replace innerHTML, which is the dangerouslySetInnerHTML we are using, but they don’t say anything about textContent.

Having said that, I’d recommend you to using one of the two methods mentioned before, dangerouslySetInnerHTML or using html2react. Regarding this last one, you can separate the <Excerpt/> and the <Date /> component as you suggest, but I think the problem is that you are defining the const Excerpt twice:

  • once at the beginning when you define
const Excerpt = libraries.html2react.Component;
  • other at the end using styled components
const Excerpt = styled.p`
  color: black;
`;

You should delete the Styled Component in order to make it work. Let us know if that solves the problem :slightly_smiling_face:

1 Like

Is it possible to style stuff using the styled component, or would I do that in the sub component Excerpt?

You can’t use Styled Components directly to the Html2React component. You could include it inside a StyledComponent. Something like this:

const Html2React=libraries.html2react.Component;
...

<StyledExcerpt className="excerpt">
  <Html2React html={item.excerpt.rendered} />
</StyledExcerpt>

...
const StyledExcerpt= styled.div`
  color:black;
`

Right but the whole point of my question is how to do this without creating extra non-semantic HTML divs, which doing this like this does.

The output of

<StyledExcerpt className="excerpt">
  <Html2React html={item.excerpt.rendered} />
</StyledExcerpt>

is

<div class="exerpt">
   <p> this is the santized text </p>
</div>

And what I’m trying to get is something morel like this:

<p class="excerpt"> this is the santized text </p>

I’m going to try to further componentize the date and excerpt stuff and see what I can get on that from there.