Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React props: Using an HTML entity within JSX dynamic content?

I have a React component, to whose props I want to assign a string that includes both JavaScript variables and HTML entities.

Some of the approaches I've attempted have resulted in the HTML entity being rendered escaped. For example, – gets rendered literally as "–" instead of as "".

Is there a way to get an HTML entity to render unescaped in a JSX dynamic content block being assigned to a React props?

Attempts Made

Tried using a template literal:

<MyPanel title={`${name} &ndash; ${description}`}> ... </MyPanel>

Problem: In the rendered output, the &ndash; is being rendered literally as "&ndash;" instead of as "".


Attempted to construct some simple JSX with no quotes:

<MyPanel title={{name} &ndash; {description}} ... </MyPanel>

Problem: This failed at compile time with a syntax error.


Tried working around the syntax error by wrapping the JSX in a <span /> element:

<MyPanel title={<span>{name} &ndash; {description}</span>} ... </MyPanel>

Problem: This works, but I'd rather avoid the superfluous <span /> element being present in the rendered output.


Tried replacing the HTML entity with a Unicode numeric character reference:

<MyPanel title={name + ' \u2013 ' + description} ... </MyPanel>

Problems:

  • This works, but (in my opinion) makes the code a little less readable. (It's more obvious that "ndash" rather than "2013" represents an en-dash character.)
  • Also, this involves +-operator concatenation, which triggers a Unexpected string concatenation prefer-template error in my team's JSLint checker; a solution that uses string interpolation instead would be better.
like image 460
Jon Schneider Avatar asked Feb 15 '18 17:02

Jon Schneider


People also ask

Can I use HTML in JSX?

Coding JSXJSX allows us to write HTML elements in JavaScript and place them in the DOM without any createElement() and/or appendChild() methods.

How do I show HTML entities in React?

To show HTML entities using React, we can wrap the HTML entity string with fragment. We wrap &sup3; in a fragment so that it'll be rendered.

Can we directly access props inside JSX?

Following approaches are there to access props inside quotes in React JSX: Approach 1: We can put any JS expression inside curly braces as the entire attribute value. Approach 2: We can use ES6 template literals.

Can props pass JSX?

Not only can JSX elements be passed as props to components, but we can also pass other components as props.


2 Answers

You can avoid the superfluous span with a Fragment:

<MyPanel title={<>{name} &ndash; {description}</>} ... </MyPanel>

This feature was introduced in React 16.2.

See the Documentation


I agree with @samanime that using the actual character is best for simple cases, but if your content is truly dynamic, I would prefer using a Fragment over either the entityToChar or dangerouslySetInnerHTML approaches.

like image 110
Luke Willis Avatar answered Sep 26 '22 22:09

Luke Willis


Here are a few options (I outlined these in a more general answer awhile back):

  1. Easiest - Use Unicode

    <MyPanel title={ `${name} – ${description}` } />
    
  2. Safer - Use the Unicode number for the entity inside a Javascript string.

    <MyPanel title={`${name} \u2013 ${description}`} />
    

    or

    <MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
    
  3. Last Resort - Insert raw HTML using dangerouslySetInnerHTML.

    title={`${name} &ndash; ${description}`}
    

    with:

    <div dangerouslySetInnerHTML={{__html: props.title}}></div>
    

const MyPanel = (props) => {
  return (
    <div>{props.title}</div>
  )
}

const MyPanelwithDangerousHTML = (props) => {
  return (
    <div dangerouslySetInnerHTML={{__html: props.title}}></div>
  )
}

var description = "description";
var name = "name";

ReactDOM.render(<MyPanel title={`${name} – ${description}`} />
, document.getElementById("option1"));

ReactDOM.render(<MyPanel title={`${name} \u2013 ${description}`} />
, document.getElementById("option2"));

ReactDOM.render(<MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
, document.getElementById("option3"));

ReactDOM.render(<MyPanelwithDangerousHTML title={`${name} &ndash; ${description}`} />
, document.getElementById("option4"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>

<div id="option1"></div>
<div id="option2"></div>
<div id="option3"></div>
<div id="option4"></div>
like image 42
Brett DeWoody Avatar answered Sep 26 '22 22:09

Brett DeWoody