Open goldylucks opened 6 years ago
@goldylucks not sure if it is possible, does the typeform library allow it?
I'll try to do some research. Thanks!
I ditched typeform, doesn't work for embedding + power using. I developed my own platform, much faster and better ;)
Same issue.
Another workaround would be to check if window is defined and do nothing if it's not.
if (typeof window !== 'undefined') {
}
Too bad because the lib looks promising :/
@goldylucks What platform did you build?
@alexgarces My use case was using your plugin with Next.js, which is a node SSR framework. https://github.com/zeit/next.js/
But so far, just loading import { ReactTypeformEmbed } from 'react-typeform-embed';
makes the app crash because it's expecting window
@Vadorequest Hi! I'm facing the same situation with next.js. and so far getting this error
Uncaught TypeError: Cannot read property 'border-radius:0;display:block;height:2px;width:25px;position:absolute;right:6px;top:6px;' of undefined
Could you please share with your solution for embed typeform if you have any? Thank you!
@dvakatsiienko My solution may not work for you, I figured that I didn't need to bother making typeform work with react, since I wanted to display it at the bottom of my page, I just followed the guidelines using "TypeForm Embed" documentation and ended up adding it outside of the react app, directly in the html body:
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<div class="typeform-widget" data-url="https://fsf-sl.typeform.com/to/YOUR_ID"
style="width: 100%; height: 700px;"></div>
<script> (function () {
var qs,
js,
q,
s,
d = document,
gi = d.getElementById,
ce = d.createElement,
gt = d.getElementsByTagName,
id = 'typef_orm',
b = 'https://embed.typeform.com/';
if (!gi.call(d, id)) {
js = ce.call(d, 'script');
js.id = id;
js.src = b + 'embed.js';
q = gt.call(d, 'script')[0];
q.parentNode.insertBefore(js, q);
}
})(); </script>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
But, I believe you can do something similar and inject this in a React component componentDidMount()
I am working with NextJS when I came across this project and tried to use it to solve some of my problems with Typeform. Well this does not solve those as it is not compatible with SSR. I found although workaround which is something I can live with. I ditched this library in a first place. Then I added <script>
-tag provided by typeform to custom _document.js
-file inside <body>
. Then I can call inside componentDidMount()
window.typeformEmbed
which gives me all features the Typeform SDK offers.
Quick guide to use Typeform Popup
Step 1:
Add <script type="text/javascript" src="https://embed.typeform.com/embed.js" />
to your _document.sj -file
Step 2:
Create component inside componentDidMount()
const typeformComponent = window.typeformEmbed.makePopup(formURL, yourCustomOptions);
Step 3:
When you want it just call
typeformComponent.open()
to show the form
In my case I store the value of makePopup()
to state and call it later on to open the form. You could just set in options given to makePopup()
open automatically by adding autoOpen: true
Hello @maario @Vadorequest actually there's a quite simple workaround for using it on Next.js on client side only: dynamic imports!
Here's an example that is working for me with the current version of react-typeform-embed.
import React from 'react';
import dynamic from 'next/dynamic';
const ReactTypeformEmbed = dynamic(() =>
import('react-typeform-embed/lib/ReactTypeformEmbed'), {
ssr: false
}
);
export default () => (
<div>
<ReactTypeformEmbed url="https://demo.typeform.com/to/njdbt5" />
</div>
);
Sorry about the ugly import path, I had to do it this way because it seems like dynamic imports don't support named exports (only default ones).
Is there a way to do this in Gatsby @alexgarces ?
I approached it a different way that doesn't require any additional packages or including the embed js code. It's true that just doing a regular 'import' of the package (and not rendering it until the client) will still cause SSR errors! HOLY S#!T This package is amateur-hour by having 'window' references even before the render of the component so that we have to workaround their incompetence. Do they not care about SSR at all? Every site that cares about SEO (any non-hobby site) always considers SSR because their site must be SSR or not get indexed by search engines. I'd first tried to only render the component on the client, but that wasn't enough. You cannot even import the component in server-side-code without errors cropping up (but not even every time. You'll change something, it works, you deploy, and then it doesn't work anymore). This package is poison by a very amateur developer, clearly. Was this a class-project by someone who has never worked in a company that requires SEO/SSR compatibility? The package doesn't even have the component as the default export. Come on, man! Step it up!
export default class TypeFormForm extends Component {
static propTypes = {
height: PropTypes.number,
}
static defaultProps = {
height: 600,
}
constructor(props) {
super(props)
this.state = { Form: null }
}
componentDidMount() {
const Form = require('react-typeform-embed').ReactTypeformEmbed
this.setState({ Form })
}
render() {
const { height, ...formProps } = this.props
const { Form } = this.state;
return (
<div style={{ height }}>
{Form && (
<Form
{...formProps}
/>
)}
</div>
)
}
}
So, basically, the react-typeform-embed package is not required/initialized until the client code is ready to render it. All TypeForm props are passed through to the component. A well-written package wouldn't need a wrapper, hopefully the author upgrades this package eventually to make it SSR-ready to appeal to professionals. If you're using a full screen pop-up, you won't want to set the height on the containing div. I put that there so that the server renders the page with a space for the form so that it doesn't suddenly reflow the page when the form comes in as the client renders. So, this is tailored to my usage, you may need to change things for how you are using typeform on your site.
I really should just make my own typeform component using their npm library, one that actually works with SSR.
Thanks to the author for making everyone your alpha testers without any regard for actual companies needing SEO/SSR using this and for announcing to the world that you just graduated!
I've been working with Next.js for a long time. There is a work around for this for static site generators like Next.js. As we know window is not accessible in a server we can access it after the component is mounted in the client side.
Add the script CDN in the custom document js file (_document.js in Next.js). I hope similar approach can be taken with other static site generators as well.
For eg. Gatsby - https://www.gatsbyjs.com/docs/custom-html/
<script type="text/javascript" src="https://embed.typeform.com/embed.js" />
Go to the page where you want to add the typeform. Use componentDidMount or useEffect to access the window object and add the typeform element to the window object itself.
useEffect(() => {
window.typeform = window.typeformEmbed.makePopup(url, options);
}, []);
Use onClick listener on the button and use the open function
() => window.typeform.open()
You can use other functions as well, I've not tried them. Just pass the arguments accordingly and use refs where you have to pass the elements as an argument.
Workaround: render component only after mounting