I am building a website with Nextjs and have my course lessons stored in a different file. In there I have String containing content like for example
taskInfo: `
<h1 className="task-section__info-header px-task pt-task-header">Hello World!</h1>
<div className="task-section__info-description px-task">
For this lesson, we will be creating a simple "Hello World!" program.
<br />
If you forgot how to do this, revisit the previous lesson.
<div className="task-section__code">
<CodeSnippet
language="javascript"
>
console.log("Hello World!");
</CodeSnippet>
</div>
`,
My goal now is to pass this string as a prop to a component and display that string on the screen with the components and the rendered HTML. I've tried things like html-to-react or unified or babel, but they all provided their own errors and didn't work. Html-To-React, for example, only converts the HTML but not the component.
I have a GatsbyJS site that I am working on where the main content source is a Wordpress install. One of the things I like to add to my sites is the ability to have placeholder areas in the site where I can control the content via the CMS. Usually I have a header_scripts area that goes at the bottom of the <head> tag, a body_scripts area that goes at the start of the <body> tag, and a footer_scripts area that goes at the bottom of the page <body>. With these three, I can usually integrate third-party add-ins pretty easily without having to do code deployments.
Sometimes I need to embed stylesheets, sometimes I need to embed script tags, and sometimes I need to throw in <meta> tags. Really the content could be anything. This data comes back as a raw string from my Wordpress GraphQL endpoint.
So now my question is, how do I get this content injected into my Gatsby site in the following places:
<html>
<head>
...
{header_scripts}
</head>
<body>
{body_scripts}
...
{footer_scripts}
</body>
</html>
I've found so far that I can just include the body_scripts and footer_scripts in a fairly regular manner in my Gatsby page template. In gatsby-node.js, I pass in the property values using the pageContext. It's kind of a bummer that they need to be wrapped in a <div /> tag, but they seem to work just fine.
import React from 'react'
export default class PageTemplate extends React.Component {
render = () => {
return (
<React.Fragment>
{this.props.pageContext.bodyScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.bodyScripts}} />
)}
{/* my page content here */}
{this.props.pageContext.footerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
)}
</React.Fragment>
)
}
}
Now for the real question. I am stumped on how to get the dynamic content from the header_scripts into the Gatsby server-side-rendering <head> tag. The closest thing I have found to being able to inject content into the head is to leverage the gatsby-ssr.js onRenderBody function. However, this seems to require pre-determined React component instances in order to function. I can't just pass it in plain raw string content and see the output in the page source:
export const onRenderBody = async ({
pathname,
setHeadComponents,
setHtmlAttributes,
setBodyAttributes,
setPreBodyComponents,
setPostBodyComponents,
setBodyProps
}, pluginOptions) => {
setHeadComponents(['<script>alert("hello");</script>'])
}
This results in an escaped string getting inserted into the <head> tag:
<html>
<head>
...
<script>alert("hello");</script>
</head>
<body>
...
</body>
</html>
I'm at a loss as to how to proceed. I can't just wrap my string in a <div /> tag like in the body because div tags can't go inside the head tag. I can't think of any head-capable HTML tags that would accept this kind of content.
The only idea I've had is to actually parse the string content into full React components. This seems daunting given the number of possible tags & formatting that I would need to support.
Am I going about this the wrong way? How can I get my arbitrary content into my Gatsby site's head tag?
It's a broad question and it will need some trials and errors to ensure that it's fully working without caveats in all scenarios but, among the things you've tried, you can add a few more options to the list to check which ones fit better.
Regarding the body_scripts and footer_scripts both can be inserted using the:
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
In any desired page or template. For the header_scripts and the meta tags (SEO), you can use the <Helmet> component. Basically, using this component, everything that is wrapped inside, it's becomes transpiled inside the <head> tag once compiled.
export default class PageTemplate extends React.Component {
render = () => {
return (
<React.Fragment>
<Helmet>
{this.props.pageContext.headerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.headScripts}} />
)}
</Helmet>
{this.props.pageContext.bodyScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.bodyScripts}} />
)}
{/* my page content here */}
{this.props.pageContext.footerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
)}
</React.Fragment>
)
}
}
However, if the data comes from a CMS, it won't be available in the SSR yet, so, one easy thing you can do is to customize the outputted HTML (html.js) that Gatsby generates in each compilation. From the docs:
Customizing html.js is a workaround solution for when the use of the
appropriate APIs is not available in gatsby-ssr.js. Consider using
onRenderBody or onPreRenderHTML instead of the method above. As a
further consideration, customizing html.js is not supported within a
Gatsby Theme. Use the API methods mentioned instead.
Run:
cp .cache/default-html.js src/html.js
Or manually, copy the .cache/default-html.js file and paste it /src folder. There you can customize the final HTML.
Just wondering what the procedure is loading an external script into a component which renders HTML?
I call a script, which returns me an unordered list which i want to use for an image carousel it looks something like this but currently isn't working
this is what i have inside my render
return(
<Slick {...settings}>
<script
type="text/javascript"
src="https://some.external.script.js"
/>
<div
class="render-html-here-from-script"
/>
<script>
SomeScript.require(['xxx'], function(arg)
{arg.loadAll().done(function(embed) {
// code here gets list and binds above in div
})}
)
</script>
</Slick>
)
the above code works fine if I just copy/paste straight into a standard HTML page
Thanks
I am looking for the best way to inject a dynamically built image as my background image. I can build the image and I can display it as a div but I want it as the background of my body.
<div className="App">
<mycomonent />
</div>
works but it is not what I want
<body styles="background-image: {mycomponent}"></body>
You can change using regular DOM object within React.
document.body.style.backgroundImage = `url("https://www.placecage.com/c/460/300")`;
Working Demo
Here's what i'm trying to do:
I have a string with html and ionic elements in my .ts file:
page_content = "<ion-card class='card-ios'><ion-card-header>Header</ion-card-header><ion-card-content>Card Content</ion-card-content></ion-card>"
then i want to inject that string in a div in the html page:
<ion-content padding class="home">
<div [innerHTML]="sanitizer.bypassSecurityTrustHtml(page_content)">
</div>
</ion-content>
the problem is that the style of the card is not applied to the content, if i insert the code directly in the html it shows fine.
with innerHTML
inserted directly
Thanks in advance.