Lazy Loading Isn’t Just for Images: What Else Can You Delay?
Pradeep

Pradeep @javascriptwizzard

About: Frontend Engineer, Learner, Tinkerer.

Location:
Cupertino, CA
Joined:
Mar 18, 2025

Lazy Loading Isn’t Just for Images: What Else Can You Delay?

Publish Date: Jun 1
11 6

When we talk about lazy loading, most developers think of one thing:

<img src="cat.jpg" loading="lazy" />
Enter fullscreen mode Exit fullscreen mode

It’s an awesome performance win — only load images when they're needed.
But what if I told you lazy loading doesn’t stop at images?

There’s a whole world of assets, components, and even logic that you can delay to give users a faster, smoother experience.

Let’s dig in. 👇


🧱 1. Lazy Loading JavaScript Modules

Modern bundlers like Webpack, Vite, and Rollup support dynamic import() for splitting your JS into chunks and loading them on demand.

Example:

button.addEventListener("click", async () => {
  const { showModal } = await import("./modal.js");
  showModal();
});
Enter fullscreen mode Exit fullscreen mode

✅ Benefits:

  • Smaller initial bundle
  • Faster initial load
  • Only load what the user interacts with

🎨 2. Lazy Loading CSS

Yes — you can lazy load styles too.

Example (with JavaScript):

const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "extra-styles.css";
document.head.appendChild(link);
Enter fullscreen mode Exit fullscreen mode

Useful for styles needed only after a user navigates to a specific section or opens a modal.

💡 Pro Tip: Tools like vite-plugin-style-import or Webpack’s code splitting can help automate this.


🧩 3. Lazy Loading Web Components or UI Sections

Using frameworks or raw JavaScript, you can defer loading complex components:

Example with React:

const Comments = React.lazy(() => import('./Comments'));

<Suspense fallback={<Spinner />}>
  <Comments />
</Suspense>
Enter fullscreen mode Exit fullscreen mode

Example without React (vanilla JS):

Load a custom element only when it enters the viewport:

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      import('./fancy-widget.js');
      observer.disconnect();
    }
  });
});

observer.observe(document.querySelector('#widget'));
Enter fullscreen mode Exit fullscreen mode

🧠 4. Lazy Execution of Expensive Logic

Not everything needs to run at page load.

  • Analytics
  • Animations
  • Non-critical API calls

Instead, defer them until idle time:

window.requestIdleCallback(() => {
  expensiveNonCriticalWork();
});
Enter fullscreen mode Exit fullscreen mode

Or delay them slightly:

setTimeout(() => {
  loadAnalytics();
}, 3000);
Enter fullscreen mode Exit fullscreen mode

🔌 5. Lazy Loading Fonts

Fonts can be large and render-blocking if not handled well.

Use font-display: swap in your @font-face CSS rule:

@font-face {
  font-family: 'MyFont';
  src: url('myfont.woff2') format('woff2');
  font-display: swap;
}
Enter fullscreen mode Exit fullscreen mode

This tells the browser to render fallback text immediately and swap in your custom font once it's loaded.


🗺 6. Lazy Loading Routes in SPAs

If you're building a single-page app with client-side routing, don’t load all pages upfront.

With tools like React Router or Vue Router:

const AboutPage = React.lazy(() => import('./About'));
Enter fullscreen mode Exit fullscreen mode

Each route gets its own chunk — users only download the code they need.


🧩 7. Lazy Hydration (Advanced)

For sites using static or SSR (like Next.js, Astro, or Qwik), consider hydrating interactivity lazily, either:

  • On user interaction (e.g., click, scroll)
  • When components enter the viewport

This can drastically reduce time to interactive (TTI).


⚠️ Caveats

Lazy loading is powerful, but:

  • Don't overdo it: delaying too much can make your app feel sluggish or unresponsive.
  • Measure: Use tools like Lighthouse, WebPageTest, or Chrome DevTools to ensure lazy loading is helping, not hurting.
  • Test fallback behavior: Always account for unsupported features or timing issues.

🧪 Final Thoughts

Lazy loading is no longer just an image optimization trick — it’s a mindset.

Load only what the user needs, when they need it.
It improves performance, saves bandwidth, and enhances UX — especially on mobile or slow connections.

So next time you ship a feature, ask yourself:

Can this wait just a little bit longer?

Chances are… it probably can.


Comments 6 total

  • Abhinav Shinoy
    Abhinav ShinoyJun 1, 2025

    Once again an awesome post! Thanks @javascriptwizzard !

  • Abhinav Shinoy
    Abhinav ShinoyJun 1, 2025

    BTW, Does requestIdleCallback wait until window load or simply whenever the main thread is idle?

    • Pradeep
      PradeepJun 13, 2025

      It doesnt wait for window load @abhinavshinoy90 it gets triggered whenever main thread is idle.

  • Nevo David
    Nevo DavidJun 1, 2025

    pretty cool breakdown tbh - i always wonder if i’m holding too much stuff back or not enough, you ever feel like there’s a good way to find that balance?

    • Pradeep
      PradeepJun 13, 2025

      Thanks @nevodavid !
      It completely depends on the specific usecase you are catering to.
      Consider factors like:

      1. SPA vs PWA vs Traditional Navigation
      2. Mobile vs Tablet vs Desktop app
      3. High bandwidth vs low bandwidth users and more...
Add comment