Stencil lazy:true: on-demand component loading without extra bundle weight
Stencil's lazy:true decorator creates a separate chunk for a component that is fetched only on first DOM use. See how to enable it, verify on-demand loading in DevTools, and avoid first-render latency pitfalls.
29 Dec 2025, 10:38 UTC

You ship a component library with 40+ web components but a page only uses three. Without on-demand loading users download JavaScript for the whole library. Stencil's lazy: true option lets you mark optional components so the compiler emits a separate chunk that is fetched only when the element first appears in the DOM.
The takeaway is that lazy loading is opt-in per component, not automatic. You decide which UI pieces are optional and pay a small first-render delay for them in exchange for a smaller initial bundle and faster time-to-interactive.
What lazy:true changes in the build
In the @Component decorator you can set lazy: true. The Stencil compiler then generates a separate ES module chunk for that component instead of including it in the main bundle. The runtime loader registers the custom element tag and issues a dynamic import() the first time the browser parses an instance of the tag.
This works with Stencil's standard ES module output and automatic code-splitting. The initial JavaScript payload stays smaller, and pages with many optional UI pieces become interactive sooner. The bundler used by Stencil, typically Rollup, must be left to keep those chunks as separate files; inlining them defeats the purpose.
Worked example: a conditionally rendered modal
Create a component and mark it lazy. Run the commands in a terminal where you have Node.js and npm available, no elevated permissions required.
npm init stencil
# choose the component starter
cd my-components
npm run generate my-modal
Edit src/components/my-modal/my-modal.tsx to enable lazy loading:
@Component({
tag: 'my-modal',
styleUrl: 'my-modal.css',
shadow: true,
lazy: true
})
export class MyModal {}
In a parent component render it conditionally:
render() {
return (
(this.showModal = true)}>Open
{this.showModal && }
);
}
Run npm start to serve the dev build locally. Open DevTools Network tab and reload. The modal's chunk should not be present initially. Toggle visibility by clicking Open. A new request for a separate .js file for my-modal appears after the interaction, and the component upgrades once the chunk arrives. Check the console for errors and confirm the component renders after load.
Trade-offs and limitations
First-render latency. The first time a lazy component appears the browser must fetch its chunk. That adds a network round-trip. Avoid lazy loading components needed for initial paint or critical above-the-fold content.
Serving and caching. Lazy loading increases request count. Serve over HTTP/2 or HTTP/3 so chunks multiplex, and set long-lived cache headers on content-addressed chunk files.
SSR hydration. With server rendering the markup can appear immediately, but interactivity waits for the lazy chunk. For SEO-critical content this can delay meaningful interaction if not handled with loading states.
Check it yourself
Audit one real page: count component chunks loaded before any user interaction, then move interaction-gated UI like modals, drawers and tabs behind conditional rendering with lazy: true. Verify the reduction by comparing the Network tab before and after the change, and keep critical UI eager.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.