React: Using a WebComponent/customElement with React

Created on 9 Nov 2016  Â·  9Comments  Â·  Source: facebook/react

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

class OrionNotificationElement extends HTMLElement {
  constructor () {
    super();

    console.log('OrionNotification');
  }
}

window.customElements.define('orion-notification', OrionNotificationElement);

export default OrionNotificationElement;

import React, { Component } from 'react';
import { default as OrionNotificationElement } from './webcomponents/orion-notification';

class OrionNotification extends Component {
render () {
  return <orion-notification/>;
}
}

Using the component causes the following error:

ReactDOMComponent.js:512 Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.(…)

Pasting the customElement definition into the console and calling document.createElement('orion-notification') creates an element. After loading react, it seems this error occurs.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/reactjs/69z2wepo/).

What is the expected behavior?

I should be able to instantiate the web component.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

Current react and current chrome.

All 9 comments

I followed the examples pointed to from this page:

https://facebook.github.io/react/docs/web-components.html

Does anyone know if this page is up to date or accurate?

This is not an issue with React. It appears that the problem is with how Babel transpiles super().

Have you tried not using ES6 classes for this, just like the example you linked to does?

For example, notice no extends or super here:

      // Define WebComponent
      var proto = Object.create(HTMLElement.prototype, {
        attachedCallback: {
          value: function() {
            var mountPoint = document.createElement('span');
            this.createShadowRoot().appendChild(mountPoint);

            var name = this.getAttribute('name');
            var url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
            ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
          }
        }
      });
      document.registerElement('x-search', {prototype: proto});

I’m closing because it is not actionable for React team. You might want to report this to Babel.

Babel's class transform does not support extending native types: https://babeljs.io/docs/usage/caveats/#classes

I was also following the examples from https://developers.google.com/web/fundamentals/getting-started/primers/customelements. This was where I was using the syntax for extending the native types; maybe I need a newer version of babel?

For example, here's a snippet from the article:

class AppDrawer extends HTMLElement {...}
window.customElements.define('app-drawer', AppDrawer);

@burtonsamograd-adsk

As @Kovensky wrote just above, Babel class transform just doesn't support extending built-ins such as HTMLElement. You should either disable class transform (and thus give up older browsers) or use Object.create() as shown above.

Object.create() is no longer a valid way to create a WebComponent. I opened #8656 to track this (rather than cram that spec behavior change in here).

Seems like I am bringing something back from the dead 😅.

@gaearon any idea how can I disable class transforming in Babel, when I am using only the react preset?

.babelrc

{
  "presets": ["react"]
}

.package.json (fragment)

  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",

Thanks for your time.

If you only use the React preset Babel won't transform classes. Unless there's some other Babel config (in parent directories or e.g. webpack options).

In my case, it's not related to babel or react. It's caused by chrome extension.

Was this page helpful?
0 / 5 - 0 ratings