How to use a different src for the same Image in NextJS?

frontend,

nextjs,

responsive

2 min read

29/04/2024

Let’s image that you need imageA for desktop and imageB for mobile screens, using the same component, just changing the image source. Sounds a little common, right? How to achieve that using NextJS?

How It Works

The AdaptiveImage component takes two image sources: one for desktop and another for mobile screens. By leveraging the tag within the element, it dynamically selects the appropriate image based on the screen size, ensuring optimal loading and rendering performance.

Key Benefits

Improved Performance
By preloading the images and specifying different sources based on screen size using media queries, AdaptiveImage minimizes unnecessary loading and rendering, thus enhancing page loading speed and overall performance.

Simplified Implementation
With a concise and intuitive API, developers can easily integrate AdaptiveImage into their Next.js applications without complex configurations. The component abstracts away the complexities of handling image adaptation, allowing developers to focus on other aspects of their projects.

Enhanced User Experience
Tailoring image content to different screen sizes enhances the user experience by delivering crisp and appropriately sized images, regardless of the device used. This approach ensures that users receive an optimized viewing experience, leading to increased engagement and satisfaction.

Leveraging HTML5 Picture Element

The <picture> element, along with the <source> tags, empowers AdaptiveImage to deliver adaptive image rendering effectively. While the <img> tag serves as a fallback for unsupported browsers, the <source> tags allow specifying multiple image sources based on media queries, enabling seamless adaptation across various devices.

import { getImageProps, ImageProps, StaticImageData } from 'next/image';
import Head from 'next/head';

const AdaptiveImage = ({
  className,
  alt = 'Hero image',
  sizes = '100vw',
  placeholder = 'blur',
  breakpoint = 640,
  desktopImage,
  mobileImage,
  style = { objectFit: 'cover' },
  ...props
}: {
  breakpoint?: number;
  desktopImage: StaticImageData;
  mobileImage: StaticImageData;
} & Partial<ImageProps>) => {
  const commonPreload = {
    rel: 'preload',
    as: 'image',
    imageSizes: sizes,
  };
  const common = { alt, sizes, className, style, placeholder, ...props };
  const { srcSet: desktop } = getImageProps({ ...common, src: desktopImage }).props;
  const { srcSet: mobile, ...rest } = getImageProps({ ...common, src: mobileImage }).props;
  const desktopMedia = `(min-width: ${breakpoint}px)`;
  const mobileMedia = `(max-width: ${breakpoint - 1}px)`;
  return (
    <>
      <Head>
        <link {...commonPreload} media={desktopMedia} href={desktopImage.src} imageSrcSet={desktop} />{' '}
        <link {...commonPreload} media={mobileMedia} href={mobileImage.src} imageSrcSet={mobile} />
      </Head>
      <picture className={className}>
        <source media={desktopMedia} srcSet={desktop} />
        <source media={mobileMedia} srcSet={mobile} />
        <img alt={alt} {...rest} />
      </picture>
    </>
  );
};

export default AdaptiveImage;
myself

Hey there, I'm Guilherme. I'm a software developer and learning passionate based in Brazil.

You can see some of my work on GitHub or read more about me on my website.