Using dangerouslySetInnerHTML in React within a Fragment

In my current project, I have a specific requirement where I need to format text in React and also include HTML rendering.

Here's an example of what I'm trying to accomplish:

import React, {Fragment} from "react";
import {renderToString} from "react-dom/server";

function FormatText(props) {
  const lines = props.children.split('\n');

  return lines.map((line, index) => (
    <Fragment key={index}>
      {line}{index !== lines.length - 1 && <br/>}
    </Fragment>
  ));
}

const content = {
  first: 'This is some text\nwith new\n\nline characters - 1',
  second: 'This is some text\nwith new\n\nline <strong>characters - <sup>2</sup></strong>',
};

function App() {
  return (
    <ol>
      <li>
        <FormatText>{content.first}</FormatText>
      </li>
      <li dangerouslySetInnerHTML={{
        __html: renderToString(<FormatText>{content.second}</FormatText>)
      }}/>
    </ol>
  )
}

This setup includes the use of the content variable which consists of \n characters and HTML. However, utilizing the renderToString function results in the HTML being converted into encoded characters, causing rendering issues.

Is there a way to effectively render HTML within a react fragment?

My preferred approach would be (although it currently does not work as expected):

function FormatText(props) {
  const lines = props.children.split('\n');

  return lines.map((line, index) => (
    <Fragment key={index} dangerouslySetInnerHTML={{__html: renderToString(
        <Fragment>
          {line}{index !== lines.length - 1 && <br/>}
        </Fragment>
      )}}>
    </Fragment>
  ));
}

Answer №1

  • <Fragment> does not add any node to the DOM and therefore
    you cannot use dangerouslySetInnerHTML on it
    . React provides this functionality to prevent adding extra nodes to the DOM when you need to return more than one from render. If something does not exist on the real DOM, you cannot manipulate it.
  • renderToString is typically used on the server-side. When performing server-side rendering, the goal is to send HTML from the server to the client. Therefore, it is best to avoid using renderToString.

The problem is that HTML does not recognize \n for line breaks, etc. It requires actual HTML tags. The recommended approach is to use FormatText, or you can simply convert \n to <br> and then use dangerouslySetInnerHTML inside the <li> tag.

const content = {
  first: 'This is some text\nwith new\n\nline characters - 1',
  second: 'This is some text\nwith new\n\nline <strong>characters - <sup>2</sup></strong>',
};

function App() {
  return (
    <ol>
      <li dangerouslySetInnerHTML={{
        __html: content.first.replace(/\n/g, "<br/>")
      }}/>
      <li dangerouslySetInnerHTML={{
        __html: content.second.replace(/\n/g, "<br/>")
      }}/>
    </ol>
  )
}

ReactDOM.render(<App/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

I hope this information proves helpful. Feel free to reach out if you have any questions.

Answer №2

Hey there, I don't believe it's feasible to directly inject formatted HTML into the DOM without using a div element.

You might find this link helpful or it could provide some guidance: https://reactjs.org/docs/dom-elements.html

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Change the code from a for-loop to use the Array#map method

I have been working on a simple JavaScript function and attempting to convert the code from using a for-loop to Array#map. I'm sharing my code in the following fiddle as I am currently learning about array map: http://jsfiddle.net/newtdms2/. function ...

Deploying Next.js on an AWS EC2 (Linux instance) Tutorial

I have successfully developed a Next.js application. My current challenge involves deploying this application on an AWS EC2 instance. I have managed to deploy it on the EC2 instance, similar to how it runs on my local development server by moving the enti ...

Calculate the time difference between the stroke of midnight on a specific date and the present moment using JavaScript, node.js, and

Looking for a way to determine if the current moment is less than 3 minutes after midnight of the next date using a JavaScript Date object (e.g. 09.08.2020 15.45). This condition should evaluate to true for times ranging from 09.09.2020 00:00 up until 09.0 ...

Experiencing a problem with value formatting while attempting to implement tremor for charts in React with Next.js version 13

import { getAuthSession } from "@/lib/auth"; import { db } from "@/lib/db"; import { Card, LineChart, Text, Title } from "@tremor/react"; import Linechart from "./LineChart"; const dollarFormatter = (value: number) ...

Obtain an individual item from the reducer array

I am working on a company reducer that will store an array of companies. To optimize performance, I aim to fetch only the necessary company object from my API when a user navigates to /company/name. This way, if a user visits the same company page multiple ...

Comparing React's defaultProps to ES6 default parameters in destructuring: the impact on performance

Recently, I encountered a dilemma regarding optimizing React performance in one of my stateless functional components. In this component, I had defined defaultProps with row: false, but I found it inconvenient as the defaultProps were placed at the end of ...

Guide to Increasing Table Index within Nested Loop in Vue.js 3

How can I increment table indices within a nested loop in Vue.js 3? I am currently working with two-level deep arrays using Vue.js, and I need an index that starts at 1 and increases for each item in the top-level array. The desired output is as follows: ...

Unable to call Ionic component function using ref in Vue3

I'm attempting to utilize the closeSlidingItems method of the IonList element in order to automatically close the sliding item after clicking a button that appears from behind once the item is slid to the right. My approach involved referencing IonLi ...

What is the best way to incorporate a variable in the find() method to search for similar matches?

I've been working on a dictionary web application and now I'm in the process of developing a search engine. My goal is to allow users to enter part of a word and receive all similar matches. For instance, if they type "ava", they should get back ...

Error: The current element cannot be clicked. Please try again

I have been attempting to trigger a click event on another button within an onClick event function. An error occurred: Uncaught TypeError: this.clickBack.current.click is not a function The React version being used is 16.8.6 constructor(props) { s ...

Issue: Error code 0308010C encountered in the digital envelope routines, indicating unsupport for the command npm run storybook

Whenever I attempt to run npm run storybook An error pops up in the terminal: Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:71:19) at Object.createHash (node:crypto:133:10) Operating System - ...

The jquery error NS_ERROR_XPC_BAD_CONVERT_JS is causing issues on Google Chrome while working fine on Firefox

Currently, I am utilizing jQuery to dynamically add fields to a form. These are considered "repeatable" fields since users can click an "add more" button. Here is the code snippet: $(".add-attacker-scores").click(function() { count = count + 1; ...

Upon inserting Node 5, an error with the code EINVALIDTYPE occurred in npm

Recently, after I upgraded to Node 5, I've been encountering an error in the terminal every time I try running anything with npm. npm -v: 2.14.12 Desperately attempting to update npm to the latest version: MacBook-Pro-de-MarceloRS:promo-auto-loan ...

The SVG image does not display in browsers other than Internet Explorer (IE)

I am encountering an issue with adding a menu toggle image in SVG format to my HTML. Unfortunately, the image is not displaying as expected. Here are screenshots for comparison between Explorer and Chrome: https://i.stack.imgur.com/74sqh.png https://i. ...

Facing a challenge with displaying an angularjs template within a popover

I am having trouble displaying custom HTML content in a popover when clicking on my "View" link. Although other content is rendering correctly, such as one with an ng-repeat inside it, my custom directive does not seem to be processed and displayed properl ...

What is the best way to switch a boolean state in React using TypeScript?

Hey there! I'm diving into the world of React and TypeScript. My goal is to toggle a boolean state (true/false) using a handler function. While I've come across solutions in ES6, I'm struggling to grasp how it can be implemented in TypeScri ...

Managing State changes efficiently in React using a single handleChange method for handling selectFields and TextFields

Seeking guidance on how to manage state changes using a single handleChange method. I am currently handling two text fields with handleChange, but I am struggling to incorporate changes from the SelectField component into the same handleChange method. Fo ...

Trouble with setting state in React using hooks

There appears to be an issue with the code below where the variable newName's state is not changing as expected. import React, { useState } from 'react' const App = () => { const [ persons, setPersons] = useState([ { name: & ...

Pause for a moment before displaying the VueJS loading screen

When using VueJS, I have implemented a loader to be displayed on each route like this: router.beforeEach((to, from, next) => { store.commit('loading', true); next(); }) However, it seems unnecessary to show the loader for a request that ...

Manipulating a DOM element in Angular 2 to alter its class attribute

I am a beginner in angular2. Here is my code: import { Component, OnInit } from '@angular/core'; @Component({ selector: 'main', template: ` <div class="current"> </div> ` }) export class MainComponent impl ...