Publishing to npmPermalink to “Publishing to npm”
To publish your component to npm, see the instructions on contributing npm packages.
Your package.json configuration should have the
You should also create a README describing how to consume your component.
Compiling with TypeScriptPermalink to “Compiling with TypeScript”
The following JSON sample is a partial
tsconfig.json that uses recommended options for targeting ES2019, enables compilation of decorators, and outputs
.d.ts types for users:
false should only be required when the
target is set to
esnext or greater, but it's recommended to explicitly ensure this setting is
When compiling from TypeScript, you should include declaration files (generated based on
declaration: true above) for your component's types in the
types field of
package.json, and ensure the
.d.ts.map files are published as well:
See the tsconfig.json documentation for more information.
Compiling with BabelPermalink to “Compiling with Babel”
Install Babel and the Babel plugins you need. For example:
Configure Babel. For example:
Publishing best practicesPermalink to “Publishing best practices”
The following are other good practices to follow when publishing reusable Web Components.
Do not import polyfills into modulesPermalink to “Do not import polyfills into modules”
Polyfills are an application concern, so the application should depend directly on them, not individual packages. The exact polyfills needed often depends on the browsers the application needs to support, and that choice is best left to the application developer using your component.
Packages may need to depend on polyfills for tests and demos, so if they're needed, they should only go in
Include file extensions in import specifiersPermalink to “Include file extensions in import specifiers”
Node module resolution doesn't require file extensions because it does a search of the file system looking for one of several file extensions if one isn't given. When you import
some-package/foo, Node will import
some-package/foo.js if it exists. Likewise, build tools that resolve package specifiers to URLs can also do this file system search at build time.
However, the import maps specification that is starting to ship in browsers will allow the browser to load modules with bare package specifiers from source untransformed, by providing a mapping of import specifiers to URLs in an import map manifest (that will likely be tool generated based on your e.g. npm installation).
Import maps will allow mapping imports to URLs, but they only have two type of mappings: exact and prefix. That means it is easy to alias all modules under a given package by mapping the package name to a single URL prefix. However, if you write imports without file extensions, it means that each file in your package would need an entry in the import map. This could greatly bloat the import map.
Thus, to prepare your source now to be optimally compatible with import maps, we recommend authoring with file extensions on imports.
Publish TypeScript typingsPermalink to “Publish TypeScript typings”
To make your element easy to use from TypeScript, we recommend that you:
HTMLElementTagNameMapentry for all elements authored in TypeScript.
.d.tstypings in your npm package.
For more information about
HTMLElementTagNameMap, see Providing good TypeScript typings.
Self-define elementsPermalink to “Self-define elements”
The module that declares the web component class should always include a call to
customElements.define() (or the
@customElement decorator) to define the element.
define() is brittle. If two different components both depend on a shared third component, and both try to define it, one will fail. This isn't a problem if an element is always defined in the same module where its class is declared.
One downside of this approach is that if two different elements use the same tag name, they can't both be imported to the same project.
Work is progressing on adding Scoped Custom Element Registries to the platform. Scoped registries allow a custom element's tag name to be chosen by the user of the component for a given shadow root scope. Once browsers start shipping this feature, it will become practical to publish two modules for each component: one that exports the custom element class with no side effects, and one that registers it globally with a tag name.
Until then, we recommend continuing to register elements in the global registry.
Export element classesPermalink to “Export element classes”
In order to support subclassing, export your element class from the module that defines it. This allows subclassing for extension purposes, as well as for registering in Scoped Custom Element Registries in the future.
For more readingPermalink to “For more reading”
For a more general guide for creating high-quality reusable web components, see the Gold Standard Checklist for Web Components.