Load Java Script on user interaction
Use dynamic import() within event listeners to load JavaScript modules only when users interact with components.
Loading JavaScript for unused features upfront increases bundle size, delays the initial page render, blocks the main thread during parsing and execution, and affects INP and TBT metrics. Loading code only when the user shows intent to use a feature keeps the initial bundle small, enables faster page load, improves INP scores, and makes features feel instant, because the code loads in parallel with the user action.
Use dynamic import() within event listeners to load modules only when needed. Common triggers include:
- Click interaction: The most common trigger.
- Hover or focus: An intent signal.
- Visibility or scroll: When the element enters the viewport.
- Idle time: Use
requestIdleCallbackorsetTimeout.
For a better user experience, preload the module on hover, before the click, so that features feel instant when clicked.
Anchor to ExamplesExamples
Click interaction:
Hover or focus, as an intent signal:
Visibility through scroll, using IntersectionObserver:
Idle time:
Real-world: chat widget.
Real-world: video player.
Real-world: defer Liquid content in dialogs.
For dialogs that contain expensive Liquid operations, such as collection queries or variant iteration, defer the server-side rendering until the dialog opens:
See Defer dialog content loading for detailed patterns on guarding expensive Liquid operations.
Preload on intent for an instant feel:
Anchor to TestingTesting
- Chrome DevTools Performance panel: Record a page load and check Scripting time in the summary. Use the Bottom-Up tab to see cost per script.
- Chrome DevTools Coverage: Drawer > Coverage. Shows unused JavaScript code execution.
- Network panel: Verify that modules load only on interaction.
- User testing: Confirm that features still work after interaction.
Anchor to ReferencesReferences
asset_urlfilter- Import on Interaction pattern - Addy Osmani
- Load non-critical resources on interaction
- AssetSizeJavaScript Theme Check
- MDN: Dynamic imports
- Defer non-critical scripts
- Defer dialog content loading
- Use import maps for module resolution