Reputation: 75
I'm trying to add a clucth.co widget to a Gatsby site, but it does not render. I've tried using react Helmet for the <script>
part, but it still does not work.
Hopefully I'm missing something simple here, but looking at other solutions I can't find anything that works.
For reference: https://clutch.co/content/add-review-widget-your-website
<script type="text/javascript" src="https://widget.clutch.co/static/js/widget.js"></script>
<div className="clutch-widget" data-url="https://widget.clutch.co" data-widget-type="7" data-height="65" data-clutchcompany-id="XXXXXXX"></div>
Upvotes: 6
Views: 2181
Reputation: 29320
You have multiple ways of inserting a third-party script in Gatsby. The problem you'll face in all of them is that you need to await that your div
:
<div className="clutch-widget" data-url="https://widget.clutch.co" data-widget-type="7" data-height="65" data-clutchcompany-id="XXXXXXX"></div>
Needs to be rendered your script won't be able to load.
Script
component (2022 update)Since the release of the Script
Gatsby component (powered by Partytown) it's much easier adding third-party scripts. Just:
import React from "react"
import { Script } from "gatsby"
function YourPage() {
return <Script src="https://my-example-script" />
}
export default YourPage
Helmet
:You said you already tried but it should. You may need to try the drop-in support that adds the gatsby-plugin-react-helmet
. Then:
<Layout>
<SEO title="Live" />
<Helmet>
<script src="https://tlk.io/embed.js" type="text/javascript"/>
</Helmet>
</Layout>
Check the compatibility issues when used with hooks.
onRenderBody
API from gatsby-ssr.js
:Gatsby exposes a setHeadComponents
function in the onRenderBody
API that you can take advantage from:
import React from "react"
export const onRenderBody = ({ setHeadComponents }, pluginOptions) => {
setHeadComponents([
<script key="tracking"
src="https://widget.clutch.co/static/js/widget.js
type="text/javascript"
async
/>,
])
}
This snippet above will insert the <script>
in the <head>
tag of the compiled HTML.
Here you have another approach using dangerouslySetInnerHTML:
setHeadComponents([
<script dangerouslySetInnerHTML={{whateveryouneedtoset}}>
])
Extracted from Unable to Inject 3rd Party Scripts in Gatsby
html.js
:You can customize even more the output of the resultant HTML by modifying the html.js
, the boilerplate that uses Gatsby to build your entire site.
Run:
cp .cache/default-html.js src/html.js
Or alternatively, copy the default-html.js
from .cache
folder into /src
and rename it to html.js
. When compiling, if the html.js
is present, Gatsby will take it to build your site based on that skeleton.
You'll have something like:
import React from "react"
import PropTypes from "prop-types"
export default function HTML(props) {
return (
<html {...props.htmlAttributes}>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{props.headComponents}
</head>
<body {...props.bodyAttributes}>
{props.preBodyComponents}
<div
key={`body`}
id="___gatsby"
dangerouslySetInnerHTML={{ __html: props.body }}
/>
{props.postBodyComponents}
</body>
</html>
)
}
HTML.propTypes = {
htmlAttributes: PropTypes.object,
headComponents: PropTypes.array,
bodyAttributes: PropTypes.object,
preBodyComponents: PropTypes.array,
body: PropTypes.string,
postBodyComponents: PropTypes.array,
}
There you can add your <script>
directly:
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<script type="text/javascript" src="https://widget.clutch.co/static/js/widget.js"></script>
{props.headComponents}
</head>
gatsby-plugin-load-script
:Just install and use the plugin:
{
resolve: 'gatsby-plugin-load-script',
options: {
src: 'https://widget.clutch.co/static/js/widget.js',
},
},
gatsby-browser.js
API:If none of the above fits you, you can still use one of gatsby-browser.js
APIs (onClientEntry
) to manually add script given a source URL:
const addScript = url => {
const script = document.createElement("script")
script.src = url
script.async = true
document.body.appendChild(script)
}
export const onClientEntry = () => {
window.onload = () => {
addScript("https://widget.clutch.co/static/js/widget.js")
}
}
Upvotes: 4
Reputation: 288
In order to not have the clutch widget disappear on route changes, I ended up running the Init
and Destroy
methods from window.CLUTCHCO
myself in useEffect
.
React.useEffect(() => {
// add widget to end of body and run it
const script = document.createElement("script")
script.type = "text/javascript"
script.src = "https://widget.clutch.co/static/js/widget.js"
script.async = true
document.body.appendChild(script)
// run script
script.onload = () => {
// @ts-expect-error Apparently we have to manually do this!! 🗑️
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
window.CLUTCHCO.Init()
}
return () => {
// @ts-expect-error Apparently we have to manually do this!! 🗑️
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
window.CLUTCHCO.Destroy()
document.body.removeChild(script)
}
}, [])
Upvotes: 3