npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-oembed-container

v1.0.1

Published

React container for locating and injecting oembed scripts in string content.

Downloads

19,137

Readme

oEmbedContainer

This package provides a React component wrapper to handle detecting and injecting script tags within HTML string content.

Build Status

Background

Content management system API endpoints like those in WordPress often return editorial content as HTML strings rather than structured data. dangerouslySetInnerHTML is required to properly render this HTML content within a React application, or else any markup embedded in that string will not display properly.

Post content however may also include <script> tags, which have no effect when injected via innerHTML per the HTML5 specification. Scripts are nullified on innerHTML to prevent cross-site scripting attacks, but this means that any content which contains a valid script as part of its HTML content will not properly render.

This issue is particularly noticeable when dealing with oEmbedded content, such as embedded Twitter or Facebook posts. Because many of these social media providers return <script> tags as part of their oEmbed response, WordPress will produce post content HTML which works fine when loaded from an application backend but which will not properly display embedded social content when rendered from React.

For example, WordPress will let you paste in a URL like https://twitter.com/reactjs/status/964689022747475968 to the editor, then via an oEmbed request will convert it to the following rendered markup:

<blockquote class="twitter-tweet" data-width="525" data-dnt="true">
<p lang="en" dir="ltr">We&#39;re relicensing React Native (including Fresco, Metro, and Yoga) under the MIT license to match React. <a href="https://t.co/Ypg7ozX958">https://t.co/Ypg7ozX958</a></p>
<p>&mdash; React (@reactjs) <a href="https://twitter.com/reactjs/status/964689022747475968?ref_src=twsrc%5Etfw">February 17, 2018</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>

These oEmbed HTML responses may not contain any scripts. If so, great! React can render that easily. But if they do, they will either contain script tags with src attributes pointing at an external JavaScript file (as in the twitter example above), or else an inline <script> tag with code that will create & inject a script into the DOM of the page as in Facebook's example:

<div id="fb-root"></div>
<p><script>
(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = 'https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.12';
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script></p>

In order to properly display inlined oEmbed content, we need to detect and inject both types of scripts.

A Note on Security

Technically what we're doing here is permitting arbitrary scripts injected into API responses to be rendered on the front-end of your site: under certain circumstances this can pose a security risk. However, these scripts would be rendered normally when loading this same markup from the server in a more traditional CMS-driven webpage rendering context.

It is up to the CMS to ensure that any scripts which make it far enough to be output on the page (or in API responses) are properly whitelisted or sanitized as necessary. Using WordPress as an example, only the responses from whitelisted oEmbed providers or content from highly authorized users may contain scripts at all; we therefore assume that any scripts inlined within the returned content are integral to the rendering of that content and should be loaded accordingly.

Installation

npm install --save react-oembed-container

This library has peerdependencies on react-dom and react v16. If you do not already have these in your project, run

npm install --save react react-dom

Usage

Import the container element into your React component:

import EmbedContainer from 'react-oembed-container';

Then use this container to wrap whatever JSX you would normally use to render the content:

render() {
  const { post } = this.props;
  return (
    <EmbedContainer markup={post.content.rendered}>

      {/* for example, */}
      <article id={`post-${post.id}`}>
        <h2>{ post.title.rendered }</h2>
        <div dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
      </article>

    </EmbedContainer>
  );
}

If you set a className on the EmbedContainer component, that class will be passed through to the rendered <div> container:

render() {
  const { post } = this.props;
  return (
    <EmbedContainer
      className="article-content"
      markup={post.content.rendered}
    >
      <p>Article text here</p>
    </EmbedContainer>
  );
}

yields

<div class="article-content"><p>Article text here</p></div>

Local Development

Run npm install to pull down the dependencies for local development. Linting with ESLint is handled through npm run lint, and the Jest tests are run with npm test.

To work on this component, either use npm link to bring it into another project for testing or else run npm run storybook within this repository to spin up a Storybook UI development environment. This environment should be available locally at localhost:6006.