react-helmet icon indicating copy to clipboard operation
react-helmet copied to clipboard

dangerouslySetInnerHTML not working on <title> tag

Open davidyeiser opened this issue 7 years ago • 11 comments

I have a page title with coded HTML entities that I would like to render as: “New Post”

It's delivered to React as: &#8220;New Post&#8221;

For rendering the title on the page I use this code and it works as expected:

<ArticleTitle><span dangerouslySetInnerHTML={{__html: post.title}} /></ArticleTitle>

Returns:

“New Post”


However, when I try to do the same thing for the <title> tag I get an [object Object] returned:

<Helmet>
  <title dangerouslySetInnerHTML={{__html: post.title}} />
</Helmet>

Returns:

<title dangerouslysetinnerhtml="[object Object]" data-react-helmet="dangerouslySetInnerHTML">“New Post” · RAM</title>

There's an original title that is set per page by the server, however as you browse around I'm using React to update it on the client-side. If I remove the server-side <title> tag, no <title> tag is rendered at all by the front end.

Is this issue related to react-helmet or something else going on?

davidyeiser avatar Oct 13 '17 11:10 davidyeiser

This is happening for me as well. Is this supported or not? If not, is there a way to get the unescaped text without 'dangerouslySetInnerHTML'?

seantjohnson-dev avatar Dec 19 '17 12:12 seantjohnson-dev

@seantjohnson-dev I came across the encodeSpecialCharacters attribute described in #184 this may be of use to you.

all9lives avatar Mar 27 '18 19:03 all9lives

Stumbled upon this one as well. I'm on client, so encodeSpecialCharacters is of no use to me. Anyone have a solution?

enrique-ramirez avatar Apr 11 '18 23:04 enrique-ramirez

I hit this today and used he.decode as recommended here.

lightstrike avatar Jul 14 '18 17:07 lightstrike

I'm not sure if this is still an issue but when receiving a string of HTML from an API that I'm trying to render in <Helmet> it doesn't work with dangerouslySetInnerHTML it does however work if I use react-html-parser. Thought I would share in case anyone else comes across this.

Found in a gist using SEOmatic and CraftQL (works with Craft's built in GraphQL server too).

It seems unclear in the docs as well as all of the issues on the topic whether or not dangerouslySetInnerHTML is supported - some clarity on how to render HTML strings in Helmet would be great!

wfendler avatar Nov 23 '19 18:11 wfendler

Got the same issue. Unfortunately, it's not enough what @wfendler made for our use case. We have more diversity in our scripts and meta tags, they could be mixed together and so on. For example,

<script>
            !function (f, b, e, v, n, t, s) {
                if (f.fbq) return; n = f.fbq = function () {
                    n.callMethod ?
                        n.callMethod.apply(n, arguments) : n.queue.push(arguments)
                };
                if (!f._fbq) f._fbq = n; n.push = n; n.loaded = !0; n.version = '2.0';
                n.queue = []; t = b.createElement(e); t.async = !0;
                t.src = v; s = b.getElementsByTagName(e)[0];
                s.parentNode.insertBefore(t, s)
            }(window, document, 'script',
                'https://connect.facebook.net/en_US/fbevents.js');
            fbq('init', '*************');
            fbq('track', 'PageView');
</script>
<noscript>
            <img height="1" width="1" style="display:none"
                 src="https://www.facebook.com/tr?id=************&ev=PageView&noscript=1" /
</noscript>

Here we got script + noscript tags string from API. But could be something different also. So we'd simply ended up with our own parser of html. ReactHtmlParser doesn't solve this as html and jsx are different. So, @KraigWalker , @cwelch5 and others, would you like to consider adding such an escape hatch, such a helmet's opened visor to let arbitrary html to pass through? I'm very keen to contribute here! I see it can look like this or smth:

<Helmet>
   <HelmetsOpenedVisor>
    {`<script async>....</script><noscript>....</noscript>`}
   </HelmetsOpenedVisor>
</Helmet>

kokushkin avatar Dec 16 '19 16:12 kokushkin

Insert Self-XSS attack here 🙃

KraigWalker avatar Dec 18 '19 07:12 KraigWalker

@KraigWalker yes, it's could be dangerous we understand it. We have a multi-tenant app and we've just done with when managers ask as add this or that here.. and you write if (Manager1) {Script1}, else if (Manager2) and so on. So we've decided we trust their scripts. We think it's acceptable level of trust here, acceptable level of risk here in our use case.

kokushkin avatar Dec 18 '19 10:12 kokushkin

Still working on this, almost finished except one broken test, but I guess I can fix it in coming days and present my pull request. By the way, thank you for tests!)) But one problem I have constantly here, it's formatting settings in the project. I deleted all my user settings and we have no workspace settings here. Despite of that, every time I run tests my tabulation changes. But it's a different issue anyway.

kokushkin avatar Dec 23 '19 10:12 kokushkin

I ran into same issues and used he.decode

import { decode } from "he"

<title>{decode(title)}</title>

Chamberlainfrancis avatar Jul 08 '22 15:07 Chamberlainfrancis

he hasn't been updated in over 4 years (Sept 2018), so I'd be wary of adopting that for security reasons

fredrivett avatar Oct 01 '22 17:10 fredrivett