Skip to content

Publishing Web Components

Web components published incorrectly cause bundling issues, break tree-shaking, require polyfills consumers don't need, or fail in different build systems. Publish ES modules directly — let consumers handle the rest.

Module format

Publish ES2017 JavaScript as standard modules. Do not bundle, minify, or transpile to CommonJS.

json
{
  "name": "my-component",
  "type": "module",
  "main": "./src/index.js",
  "module": "./src/index.js",
  "exports": {
    ".": "./src/index.js"
  }
}

Set both "main" and "module" to the same entry point. Use .js extensions (not .mjs). The "type": "module" field tells Node.js and bundlers that all .js files in the package are ES modules.

Code practices

Do:

  • Use bare import specifiers for dependencies: import { LitElement } from "lit"
  • Include file extensions on local imports: import "./utils.js"
  • Self-register custom elements: customElements.define("my-element", MyElement)
  • Export element classes for subclassing
  • Publish a custom-elements.json manifest
  • Include TypeScript declarations (.d.ts files)

Don't:

  • Import polyfills into your modules — polyfills are the consumer's responsibility
  • Include bundler-specific transforms or config in your source
  • Depend on a specific build tool being present

What consumers handle

The consumer — not the package — decides:

  • Which browsers to support
  • Whether to polyfill
  • How to bundle and minify
  • Whether to transpile to older JS versions

If you bundle, you've made those decisions for them and broken the flexibility that makes web components composable.

Checklist

  • [ ] "type": "module" in package.json
  • [ ] "main" and "module" point to the same ES2017 entry point
  • [ ] .js extensions on all source files
  • [ ] File extensions included in all local import statements
  • [ ] Element classes exported for subclassing
  • [ ] Elements self-registered with customElements.define()
  • [ ] custom-elements.json manifest included
  • [ ] TypeScript declarations included
  • [ ] No polyfill imports in source files
  • [ ] Source not bundled or minified

See also