July 10, 2025

/

Prevent layout shift caused by image loading

When images are loaded after the initial render, they often cause layout shifts (unexpected movement of content), which negatively impacts the user experience. In this article, we’ll walk through a simple and effective approach to solving this problem using an image-containing popup example.

Problem

In the video below, you can see that when the user clicks the “Size guide” button, a popup opens, but since the image takes time to load, the layout jumps unexpectedly.

The loading of the popup has been intentionally delayed.

Solve

To fix the problem, we take the following steps:

1. Track image loading state

We use a useState hook to track whether the image has finished loading:

Terminal window
const [imageLoaded, setImageLoaded] = React.useState(false);
const handleLoadImage = () => {
setImageLoaded(true);
};

This state will be updated once the image fires the onLoad event.

2. Conditionally show the popup based on load state

We use the classNames utility to conditionally apply a class when the image is loaded:

Terminal window
<Popup
show={showChartPopup}
onClose={() => setShowChartPopup(false)}
className={classNames("chart-popup", {
"chart-popup-loaded": imageLoaded,
})}
>

This allows us to control when the popup becomes visible based on whether the image has been fully loaded.

3. Use CSS to control visibility

In the CSS, we define .chart-popup to be hidden by default, and only show it when the image has loaded:

Terminal window
.chart-popup {
display: none;
}
.chart-popup-loaded {
display: block;
}

This prevents any content from being displayed or jumping until the image is ready.

4. Full Component Code

Here is the complete component:

Terminal window
import React, { type FC } from "react";
import { Popup } from "ui-kit";
import classNames from "classnames";
export const SizeChartPopup = (sizeChartUrl: string) => {
const [showChartPopup, setShowChartPopup] = React.useState(false);
const [imageLoaded, setImageLoaded] = React.useState(false);
const handleLoadImage = () => {
setImageLoaded(true);
};
return (
<>
<button onClick={() => setShowChartPopup(true)}>
Size guide
</button>
<Popup
show={showChartPopup}
onClose={() => setShowChartPopup(false)}
className={classNames("chart-popup", {
"chart-popup-loaded": imageLoaded,
})}
>
<img
src={sizeChartUrl}
alt="Product size chart"
onLoad={handleLoadImage}
/>
</Popup>
</>
);
};

Result

Here’s the improved version, where the popup appears only after the image has loaded — smooth and stable:

Conclusion

Image loading can easily lead to unexpected layout shifts, especially in modals or popups. In this post, we:

  • Tracked when the image was loaded,
  • Showed the popup only after the image was ready,
  • Prevented visual instability using a simple CSS toggle.

Although it’s a small change in code, it has a significant impact on perceived performance and usability — particularly on mobile devices or slower networks.