Create-react-app: Custom Elements hello world throws error

Created on 1 Oct 2017  路  7Comments  路  Source: facebook/create-react-app

Is this a bug report?

Yes

Can you also reproduce the problem with npm 4.x?

Yes

Which terms did you search for in User Guide?

Custom Elements, Web Components. No results.

Environment

  1. node -v: v8.6.0
  2. npm -v: 5.3.0
  3. yarn --version (if you use Yarn): N/A
  4. npm ls react-scripts (if you haven鈥檛 ejected): N/A

Then, specify:

  1. Operating system: macOS 10.12.6
  2. Browser and version (if relevant): Chrome Canary 63.0.3223.8 (also fails on Stable)

Steps to Reproduce

  1. Create a file containing the following "hello world" Custom Element:
class HelloWorld extends HTMLElement {
  connectedCallback() {
    this.innerHTML = "Hello world";
  }
}

customElements.define('hello-world', HelloWorld)
  1. import this file (e.g. import './hello-world.js) into any React component and use it: <hello-world />

Expected Behavior

Text "hello world" is rendered on screen.

This correct behavior is observed when using the custom element outside of React (included in repro repo), i.e.:

<!doctype>
<body>
<hello-world />
<script src='hello-world.js'></script>
</body>

Actual Behavior

Text isn't rendered, console error is shown: Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

Reproducible Demo

Example minimal CRA project: https://github.com/owencm/custom-elements-issue

Running it demonstrates the issue.

Most helpful comment

Looping back around to this issue. If anyone runs across it, you can fix the error by including the custom-elements-es5-adapter.js detailed here: https://reactjs.org/docs/web-components.html#using-react-in-your-web-components

All 7 comments

Looking into this, I think it's because we're transpiring ES6 classes by default, but customElements.define only works with ES6 classes.

Not sure of the solution though...

Rob Dodson talks about this issue in the context of Angular here: https://youtu.be/Ucq9F-7Xp8I?t=7m57s

Sounds like the solution is to use Webpack to bundle in https://github.com/webcomponents/webcomponentsjs/blob/master/custom-elements-es5-adapter.js without transpiling.

Yep, this isn't expected to work with Babel.
You will probably get a better answer from the community who use custom elements.

FWIW, using this babel plugin https://github.com/github/babel-plugin-transform-custom-element-classes seems to fix the issue. The problem is Babel can't properly extend built-ins like HTMLElement, Array, etc.

Looping back around to this issue. If anyone runs across it, you can fix the error by including the custom-elements-es5-adapter.js detailed here: https://reactjs.org/docs/web-components.html#using-react-in-your-web-components

Looping back around to this issue. If anyone runs across it, you can fix the error by including the custom-elements-es5-adapter.js detailed here: https://reactjs.org/docs/web-components.html#using-react-in-your-web-components

This solved my issue with Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function. In my case I was accidentally transpiling 'custom-elements-es5-adapter.js' with gulp.

Using Webpack there. Tnx to @robdodson avice added those 2 plugins:
module: { rules: [ { test: /\.js$/, use: [ { loader: 'babel-loader', options: { presets: ['es2015'], plugins: ['transform-custom-element-classes', 'transform-es2015-classes'] }, } ], }, { test: /\.scss$/, use: extractPlugin.extract({ use: ['css-loader', 'sass-loader'] }), }, ] },

to my webpack.config.js. Works like a charm.

Was this page helpful?
0 / 5 - 0 ratings