logo ce-autoloader

Load web components on demand
if and when they're needed.

About

The ce-autoloader is a lightweight web Components lazy loader.

Checkout the demos below to see how it works, and the documentation for more details on how to use it.

Get started

It's just 3 steps. No build tools required!

Install via npm or CDN
npm install ce-autoloader
Define your catalog
import CERegistry from 'ce-autoloader';

const registry = new CERegistry({
	catalog: {
		'my-component': () => import('./my-component.js')
	}
});
Add <my-component> on the body HTML
<my-component loading="visible">World</my-component>

Examples

Documentation

Universal

Built to load any standard Web Component, regardless of framework.


Because ce-autoloader targets the standard Custom Elements API, it doesn't care how your component was built. You can mix and match components from React, Vue, Svelte, Lit, or Vanilla JS in the same page without any problems.

The example below are three components with different frameworks but sharing the same state!


Loading Strategies

Fine-tune component loading for every unique use case.


The loading attribute defines the strategy for when a component is loaded. By default, components use the visible strategy to maximize initial performance.

Eager

Downloads the module as soon as it's found in the DOM. Use this for critical "above the fold" components like navigation headers or hero sections.

Eager strategy

Visible (Default)

Components are downloaded and defined only when they enter the viewport, using a Intersection Observer. Perfect for content "below the fold" to keep initial page weight low.

Click

The module is fetched when a user clicks or touches the element. Ideal for heavy UI widgets like maps, complex editors, or modal content.

Click to load

Custom

Any custom string (e.g., loading="lazy-load") can be used as a loading strategy, and triggered manually via registry.upgrade('lazy-load'). This is useful for custom workflows that don't fit into the built-in strategies.

* custom (click) *

Custom Loaders

Tailor the loader to your specific workflow.


Don't want to register 250 components one by one? we got you. Wildcard Loaders allow you to customize the loader to fit your needs.

In this example, we registered a loader for nord-*. The browser sees <nord-qrcode>, and calls our loader, that fetches the correct module from the CDN.

/**
 * Custom loader for the Nord Health components
 */
"nord-*": async (full_name) => {
    // 1. Extract the specific component name (e.g., 'qrcode' from 'nord-qrcode')
    const [, namespace, name] = full_name.match(/^([a-z]+)-(.*)/);

    // 2. Resolve the module URL (dynamic import)
    const module = await import(/* @vite-ignore */ `https://esm.sh/@nordhealth/components/lib/${capitalize(name)}.js`);

    // 3. Define the component if not already registered
    if (!customElements.get(full_name)) {
        customElements.define(full_name, module.default);
    }
    return module
},

Now, every time the browser sees a tag with prefix nord tag, it will automatically load the component from the esm CDN.

<nord-qrcode>
<nord-select>
<nord-date-picker>
Open menu (⌘+K)
<nord-command-menu>
Canine Feline Rodents
<nord-tag-group>

Animations & Transitions

Define exactly how and when components surface.

Web components should feel like a native part of the page, not an afterthought. Orchestrate how elements surface with coordinated entry patterns that eliminate layout shift and create a fluid, intentional experience from the first frame.

Every component moves through a predictable state machine that you can style with CSS :not(:defined) → [ce="loading"] → [ce="defined"]


Placeholder state :not(:defined)

The custom element is in the DOM but the browser doesn't know its behavior yet. Use this to set min-height or aspect-ratio to reserve space on the page.

I'm a :not(:defined) element

Loading state [ce="loading"]

Triggered when the module is being loaded. This is the perfect time to show a Skeleton Loader or a progress indicator.

loading element

Interactive state [ce="defined"]

The component is defined and upgraded to a fully interactive web component. Use this to trigger a final "fade-in" or entrance animation.

A interactive element



The CSS View Transitions API are supported out of the box, and allow to create a seamless transition when the component is defined. Check out the demo below.

Native Telemetry & Insights

With telemetry baked into the core, you get deep visibility into load times and execution overhead using native browser APIs.

Error Fallbacks & Resilience


Define your own fallback component via fallback, that is displayed when a module throws an error during loading.

Additionaly, the attribute [ce=error] is also set on the component, allowing you to style it differently when an error occurs.

And you can also handle it manually by setting hooks.error on the constructor

FAQ (Perguntas Frequentes)

Why web components?

Web components with light-dom&css variables are the GOAT! They are the only way to reuse components across frameworks, and since they're part of HTML spec, they'll still work in 20 years.

Aren't you tired of recreating the same components over and over again every 5 years with the new shiny framework? Let's stop this madness!

⚛️ How to use this with react/vue/svelte/etç?

Vue and Svelte already export web-components out of the box!

Only React is purposefully missing this feature, so you need to use a library like remount or react-to-web-component.

import r2wc from "@r2wc/react-to-web-component"

const Greeter = ({ name }) => {
	return <div>Hello, {name}!</div>
}

export default r2wc(Greeter, {
	props: {
		name: "string",
	}
});

					

🚀 Wait, isn't this like Astro?

Yes and No. Both use the "Island Architecture" concept to reduce JS bloat, but they are :

  • Astro (Server-First): Renders at build time or at server. Great for new apps.
  • ce-autoloader (Client-First): Runs at runtime. Great for adding islands to existing Python, Ruby, Elixir or static HTML pages.

🚀 What's the performance like?

Glad you asked! Core Web Vitals with ce-autoloader matches or exceeds SSR frameworks like Next.js. Don't believe me? This is the score of the page you're reading now:

Core Web Vitals