Web Components Open Source Polyfill JavaScript

ArkeyJS: Custom Elements Polyfill

A lightweight polyfill that bridges Custom Elements spec v0 and v1, allowing existing components to run consistently across browsers during the web components transition period.

Role: Creator & Maintainer
Timeline: 4 months
Type: Open Source

The Challenge

In 2016, the Custom Elements specification underwent a major revision from v0 to v1, introducing breaking changes. Organizations with existing web component libraries faced:

  • • Incompatibility between v0 and v1 APIs
  • • Browser support fragmentation
  • • Need to rewrite thousands of components
  • • Risk of breaking production applications
  • • No clear migration path

The Solution

Created a lightweight polyfill that provides a compatibility layer between Custom Elements v0 and v1, allowing components written in either spec to work in any browser.

Example Usage

// Define a custom element using v1 API
class MyElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }
  
  connectedCallback() {
    this.shadowRoot.innerHTML = '<p>Hello World</p>';
  }
}

// Register with ArkeyJS
customElements.define('my-element', MyElement);

// Works in all browsers, even those with only v0 support

Key Features

  • • Bidirectional compatibility (v0 ↔ v1)
  • • Minimal performance overhead
  • • No dependencies
  • • 1KB minified + gzipped
  • • Lifecycle callback mapping
  • • Shadow DOM support
  • • Attribute observation

Browser Support

  • • Chrome 36+
  • • Firefox 31+
  • • Safari 9+
  • • Edge 13+
  • • Opera 23+
  • • Mobile browsers

Technical Challenges & Solutions

Challenge 1: Lifecycle Callback Mapping

v0 and v1 use different lifecycle callback names and timing.

v0: createdCallback, attachedCallback, detachedCallback
v1: constructor, connectedCallback, disconnectedCallback

Solution: Created a proxy layer that detects which API is being used and translates callbacks accordingly, ensuring proper execution order and timing.

Challenge 2: Constructor Restrictions

v1 spec requires calling super() in constructor and prohibits certain operations before it.

Solution: Implemented a wrapper that handles constructor initialization differently based on browser capabilities, deferring operations when necessary.

Challenge 3: Performance Overhead

Polyfills can introduce significant performance penalties, especially with many components.

Solution: Used feature detection to apply polyfill only where needed, and optimized hot paths with memoization and lazy initialization.

Architecture

1. Feature Detection Layer

Detects browser capabilities and determines which polyfill strategies to apply.

2. API Translation Layer

Maps between v0 and v1 APIs, handling lifecycle callbacks, registration, and upgrades.

3. Registry Management

Maintains a unified registry of custom elements, handling name conflicts and upgrades.

4. Mutation Observer

Watches DOM for custom element insertion/removal to trigger appropriate callbacks.

Results & Impact

95%
Browser compatibility
1KB
Minified + gzipped

Key Outcomes

  • • Enabled gradual migration from v0 to v1 without breaking changes
  • • Saved organizations months of rewrite work
  • • Adopted by multiple enterprise component libraries
  • • Featured in web components community resources
  • • Contributed to web standards discussion

Lessons Learned

  • Standards evolve: Building for web standards requires flexibility and forward-thinking to handle spec changes.
  • Performance matters: Even small overhead multiplies when dealing with hundreds of components. Feature detection and optimization are crucial.
  • Documentation is key: Clear migration guides and examples were as important as the code itself for adoption.
  • Community feedback: Open source projects benefit immensely from real-world usage feedback and edge case discovery.