Lazy-load a heavy Stencil component with loadComponent and dynamic import
Keep heavy Stencil components out of the initial bundle by exporting them correctly and loading them with loadComponent or on first render. Verify with build output and network requests.
12 Jan 2026, 18:10 UTC

Heavy charts, data grids and rich editors inflate the initial bundle and delay first paint. In Stencil you can keep those components out of the main bundle and fetch them only when needed. The practical takeaway is to use Stencil’s code‑splitting with dynamic import() and the loadComponent helper so the component is registered on demand, not at startup.
Desired outcome
A component such as heavy-chart is built as a separate chunk. The main bundle does not reference it. The chunk is requested only after you explicitly call loadComponent or when the element is first rendered in the DOM. After load the component behaves like any other Stencil component.
Prerequisites
- A Stencil app with
stencil.config.tsat the project root. - The component lives in
src/componentsand is exported as a default class. Stencil expects a kebab‑case tag name that matches the file name. - Target browsers support dynamic import(). If you must support IE11, a dynamic import polyfill and web components polyfills are required. Modern browsers need no extra config.
Dynamic import is a JavaScript feature that loads a module at runtime. Stencil uses it to create separate chunks for components that are not referenced eagerly.
Procedure
Create the component with a correct export
Create src/components/heavy-chart/heavy-chart.tsx. The file must export a default class decorated with @Component and a tag name in kebab‑case.
import { Component, h } from '@stencil/core';
@Component({
tag: 'heavy-chart',
styleUrl: 'heavy-chart.css',
shadow: true
})
export default class HeavyChart {
render() {
return Heavy chart placeholder;
}
}
If the default export is missing or the tag name does not match the file, Stencil emits a build warning and runtime loading can fail.
Configure build targets if needed
Open stencil.config.ts at the project root. For modern browsers the default config is sufficient. If you need ES5 output, set buildEs5: true and ensure polyfills for dynamic import are provided for legacy browsers.
// stencil.config.ts
export const config = {
namespace: 'my-app',
buildEs5: false,
};
Do not change the components directory layout. Keeping the component under src/components allows the build system to detect it for splitting.
Manual load on demand
When you control when the component appears, import the helper and load it before inserting the element.
import { loadComponent } from '@stencil/core';
async function showChart() {
await loadComponent('heavy-chart');
const el = document.createElement('heavy-chart');
document.getElementById('chart-host').appendChild(el);
}
Run this in a module script in the browser or in a Stencil component method. The call returns a promise that resolves after the component definition is registered.
Automatic load on first render
If you render <heavy-chart></heavy-chart> conditionally, Stencil will request the chunk the first time the element is connected. No manual call is required. This is useful for below‑the‑fold sections.
@State() show = false;
render() {
return (
<>
this.show = true}>Show chart
{this.show && }
);
}
The component is only fetched after show becomes true.
Expected checks
Build inspection. In a terminal at the project root run:
npm run build
Inspect the www/build output. The lazy component should appear as a separate chunk file and should not be referenced by the main bundle.
Runtime inspection. Open the app in a browser and use the Network tab. Trigger the component via the button or via loadComponent. You should see a network request for the chunk after the trigger, not during initial load.
Console check. Look for errors about missing exports or failed imports. A clean console after the component loads indicates correct registration.
Limitations and recovery
Dynamic import is not supported in IE11 and older browsers. If those browsers are required, provide a polyfill such as @webcomponents/webcomponentsjs and a dynamic import shim. Without it the lazy load will fail.
If the component fails to load, verify the default export and tag name. Rebuild after fixing the export. As a fallback you can import the component eagerly in the parent module, which removes code‑splitting but restores functionality.
Changing stencil.config.ts affects the whole build. Keep a copy of the original config before toggling buildEs5 or adding polyfills, so you can revert if bundle size or runtime behavior changes unexpectedly.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.