Add Iframely to React

Known issue

React sets HTML via innerHTML. Per HTML5 specification, any <script> tag is ignored. It means that rich media from publishers like Twitter, Instagram, Facebook and TikTok will not work out-of-the-box and require a hosted iFrame.

Please read details about innerHTML issue and our suggested general solution for it in our &omit_script=true guide. This guide will provide React-specific instructions only.

The issue affects any scripted third-party rich media such as Twitter, Instagram, Facebook, TikTok, Imgur and GitHub Gists, and Iframely interactives — summary cards and lazy-loaded players.

Because we still need to listen to the control events posted by iFrames, we provide our embed.js script. It is a single script that to make an exception for and add to the page yourself.

The approach

Assuming you get your HTML codes from us via API calls:

  • The fix involves putting all rich media that requires it into a hosted iFrame.
  • For this, add &omit_script=1 parameter to your API requests.
  • The parameter will make sure that your HTML codes link only to iFrames, native or Iframely-hosted.
  • Add our embed.js as a single third-party script for correct iFrame sizing.
  • Use dangerouslySetInnerHTML to properly render rich media HTML content within your React application. Otherwise, the HTML markup will not display properly.
  • Run Iframely’s loader for each element if needed.

Fetching HTML code

Fetching of HTML code can be done in multiple ways. See our general recommendation for server-side API calls to oEmbed or Iframely API and serving the HTML from your cache.

If you absolutely need to make API calls from the client, please send requests to the CDN shield cdn.iframe.ly/api/…, or via your own CDN distribution.

There is also an option to create HTML templates and skip API calls altogether. If the layout shift is not a concern, please read this approach embed.js documentation. You’ need to run Iframely’s loader for each of your elements; see next.

Add embed.js script

When you &omit_script=1, Iframely omits our own embed.js too. You’ll need to add embed.js script to your page yourself.

It is required to adjust the sizes of the iFrames correctly and to handle other events.

dangerouslySetInnerHTML

dangerouslySetInnerHTML is required to render this HTML content within a React application correctly, or else any markup embedded in that string will not display.

Naming means making sure you trust the source. dangerouslySetInnerHTML is safe when you use it with &omit_script because there will be no third-party scripts (and they are not executed by React anyway).

Run iFrame loader

You might need to run Iframely’s loader for lazy-loaded content explicitly. It depends on whether window.iframely is available before or after your iFrames are loaded. Because it is asynchronous, execute it every time you add an element to be safe:

window.iframely && window.iframely.load();

If you implement a class, trigger Iframely loader either in componentDidMount, or componentDidUpdate, depending on your lifecycle.

From React: “Do note that componentDidMount will however not be called on component updates”.

Example component

import React, { useEffect, useState } from 'src/data/docs/react';

const KEY = 'MD5_HASH_OF_YOUR_API_KEY';

export default function Iframely(props) {
  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [html, setHtml] = useState({
    __html: '<div />',
  });

  useEffect(() => {
    if (props && props.url) {
      fetch(`https://cdn.iframe.ly/api/iframely?url=${encodeURIComponent(props.url)}&key=${KEY}&iframe=1&omit_script=1`)
        .then((res) => res.json())
        .then(
          (res) => {
            setIsLoaded(true);
            if (res.html) {
              setHtml({ __html: res.html });
            } else if (res.error) {
              setError({ code: res.error, message: res.message });
            }
          },
          (error) => {
            setIsLoaded(true);
            setError(error);
          },
        );
    } else {
      setError({ code: 400, message: 'Provide url attribute for the element' });
    }
  }, []);

  useEffect((props) => {
    window.iframely && window.iframely.load();
  });

  if (error) {
    return (
      <div>
        Error: {error.code} - {error.message}
      </div>
    );
  } else if (!isLoaded) {
    return <div>Loading…</div>;
  } else {
    return <div dangerouslySetInnerHTML={html} />;
  }
}