Juan Beldi

Juan Beldi

Posted on Oct 12, '24

Using the picture element in Next.js

Creating the ResponsiveImage component

On your components folder create a new component file, I'll be naming mine: ResponsiveImage.tsx.

Import getImageProps and create the base for the component:

import { getImageProps } from 'next/image';

export const ResponsiveImage = () => {
return <></>;
};

Now I'm going to add some types for this component's prop, I'm going with a pretty basic type for brevity.

// Import base image props type
import { getImageProps, type ImageProps } from 'next/image';

// We'll be using src as the source of truth for the image
type ResponsiveImageProps = ImageProps & {
desktopSrc: string;
};

export const ResponsiveImage = ({
// Extract src and desktopSrc from props spread
src,
desktopSrc,
...props
}: ResponsiveImageProps) => {
return <></>;
};

Moving forward, we'll now extract the props from the sources and apply common props.

import { getImageProps, type ImageProps } from 'next/image';

type ResponsiveImageProps = ImageProps & {
desktopSrc: string;
};

export const ResponsiveImage = ({
src,
desktopSrc,
...props
}: ResponsiveImageProps) => {
const { props: mobileImageProps } = getImageProps({ src, ...props });
const { props: desktopImageProps } = getImageProps({
src: desktopSrc,
...props,
});

return <></>;
};

And finally we're going to use this new data in our template:

import { getImageProps, type ImageProps } from 'next/image';

type ResponsiveImageProps = ImageProps & {
desktopSrc: string;
};

export const ResponsiveImage = ({
src,
desktopSrc,
...props
}: ResponsiveImageProps) => {
const { props: mobileImageProps } = getImageProps({ src, ...props });
const { props: desktopImageProps } = getImageProps({
src: desktopSrc,
...props,
});

return (
<picture>
<source
// Breakpoint at which point the image will switch
media="(min-width: 1280px)"
srcSet={desktopImageProps.srcSet}
/>

// Spread on your main image (I'm going mobile first, so I do it for the mobileImage)
<img {...mobileImageProps} />
</picture>
);
};

Usage is pretty straight forward, you just use it like the Image component!

<ResponsiveImage
alt="Image alt"
src="/mobile-image.jpg" // Base image
desktopSrc="/desktop-image.jpg" // Desktop breakpoint image
fill // I'm using fill for simplicity
// Add other Image props as needed
/>

Testing it out

  • Open the page in a browser and access developer tools.
  • Navigate to the Network tab.
  • Reload the page and observe image requests:
    • You should see a single image request initially.
  • Resize the browser window:
    • Cross the 1280px breakpoint to trigger image switch.
    • Observe a new image request for the desktop version.
  • Reload the page while at desktop size:
    • Verify only one image request (desktop version) is made.



That's it, hope you liked it!