Performant Images with <Img> and <Source>

Read time: 2 minutes
Mitchell Christ
Mitchell Christ
twin girls, one wearing a Dr.Suess shirt with the text "Img" and the other twin "Source", film still from the horror movie The Shining by Stanley Kubrick

Serving images efficiently can get pretty complex.

This starter template comes included with an <Img> component to help serve your Sanity CDN images efficiently, without having to deal with all the complexity.

Benefits

  • Stupid simple setup.
  • Excellent resolution AND performance.
  • Art direction is as simple as adding <picture> and <Source>.

How to use

Basic usage

<Img image={image} />	// `alt` can be included in the image object

<Img
	// πŸ‘‡ required props
	image={image}

	// πŸ‘‡ recommended props
	imageWidth={600}	// max width (in pixels) to display image
	className="max-w-[450px]"

	// πŸ‘‡ other optional props
	imageSizes={[...]}	// number[]; override the generated `srcset` values
	alt="..."
	loading="eager"
	draggable={false}
	options={{ imageBuilder: (b) => b.blur(10) }}	// Sanity image builder methods
/>

Which will output:

<img
	src="https://cdn.sanity.io/images/<...>.png?w=600&auto=format"
	srcset="
		https://cdn.sanity.io/images/<...>.jpg?w=120&auto=format 120w,
		https://cdn.sanity.io/images/<...>.jpg?w=160&auto=format 160w,
		https://cdn.sanity.io/images/<...>.jpg?w=200&auto=format 200w,
		https://cdn.sanity.io/images/<...>.jpg?w=240&auto=format 240w,
		https://cdn.sanity.io/images/<...>.jpg?w=320&auto=format 320w,
		https://cdn.sanity.io/images/<...>.jpg?w=400&auto=format 400w,
		https://cdn.sanity.io/images/<...>.jpg?w=480&auto=format 480w,
		https://cdn.sanity.io/images/<...>.jpg?w=520&auto=format 520w,
		https://cdn.sanity.io/images/<...>.jpg?w=560&auto=format 560w,
		https://cdn.sanity.io/images/<...>.jpg?w=600&auto=format 600w
	"
	width="600"	// based on `imageWidth` prop
	height="533"	// automatically calculated
	alt="..."
	loading="eager"
	decoding="async"
	class="max-w-[450px]"
>

Art direction

Have a landscape (wide) image, but want to swap with a portrait (tall) image on mobile?

Voila πŸͺ„

<picture>
	<Source
		image={imageMobile}
		imageWidth={1200}
		// πŸ‘‡ optional
		media="..."	// default: '(max-width: 768px)'
	/>

	<Img
		image={image}
		imageWidth={1800}
	/>
</picture>

In the above example, image will be displayed by default, until the viewport becomes smaller than 768px where it then gets swapped with imageMobile.

Performance, Performance, Performance

<Img> is able to serve your Sanity CDN images at high resolution without impacting performance (and vice versa), largely thanks to the srcset attribute.

It is highly recommended to set imageWidth with a value just largerβ€”perhaps 1.5xβ€”than the width you'd want to display your images (in pixels), along with setting a max-width value with CSS.

For example, for an image to be displayed at 450px wide, set as follows:

className="max-w-[450px]"
imageWidth={600}

The <Img> component, along with other code best practices, helps contribute to SanityPress's 98+/100 lighthouse scores.

Under the hood

The source code for both <Img> and <Source> can be found within the Next.js frontend, where you'll see the code relies on a couple of functions, courtesy of the following dependencies:

The Geico commercial caveman wearing a collared business shirt, with a pssh facial expression in disgust and embarrasment, handed a paper with the text "Img", sitcom style film still
So easy a caveman can do it.β„’