This is a handy component for rendering responsive Sanity images. It has a simple but flexible API -- all you need to do is pass in a Sanity image asset and it will:
- Generate two
srcSets - one in the original file format, another in.webp. - Lazy load the image only when its container is within the viewport
- Provies a simpler way to write a resposive
sizesattribute without having to type in your media queries. - Lighthouse benefits:
- Images are properly sized and use
webpwhen available - Lazy-loaded images mean faster load times
- The
RatioPaddingcomponent ensures that there is no layout shift once the image loads
- Images are properly sized and use
Plus much more, look at the ImageProps definition for more info!
This takes care of all of its src, srcSet and sizes parsing within the component. Instead of using something like sanityImageUtil every time you make an <Img />, you can just pass in the image data and the rest will be taken care of. For instance, this is how images are rendered in Tablet:
<Img
className="...the class names..."
alt={Language.t('Global.editorImageAlt', { name })}
sizes="(maxWidth: 768px) 400px, (maxWidth: 1080px) 300px, 300px"
src={sanityImgUtil(teamMember.avatarImage, 400)}
srcSet={sanityImgSrcSetUtil(
teamMember.avatarImage,
400,
300,
300
)}
dimensions={
teamMember.avatarImage.metadata &&
teamMember.avatarImage.metadata.dimensions
}
crop={teamMember.avatarImage.crop}
/>
<Img
className="...the class names..."
alt={Language.t('Global.editorImageAlt', { name })}
sizes="(maxWidth: 768px) 400px, (maxWidth: 1080px) 300px, 300px"
src={sanityImgUtil(teamMember.avatarImage, 400)}
srcSet={sanityImgSrcSetUtil(
teamMember.avatarImage,
400,
300,
300
)}
/>With this component, we can simplify all of this and make images across the site more consistent. (It's easy to forget to use sanityImgUtil every time!)
<SanityImage
className="...the class names..."
alt={Language.t('Global.editorImageAlt', { name })}
sizes={['400px', '300px']}
image={teamMember.avatarImage}
/>
<SanityImage
className="...the class names..."
alt={Language.t('Global.editorImageAlt', { name })}
sizes={['400px', '300px']}
image={teamMember.avatarImage}
/>if you're using Next.js, theirnext/imagecomponent takes care of (most) of this on its own, you don't need to use any of this!- Oops! Actually,
next/imageonly does this for statically imported images, i.e. images that are in yourpublicdirectory.
- Oops! Actually,
- To get the aspect ratio, be sure to include the asset's
metadatain your Groq query. _To reduce network request payloads, be sure to request onlymetadata.dimensions. Sanity image metadata also includes a fairly largepaletteobject, as well as aLQIP- a low quality image preview, that is simply image data stored in a string.- _however, if you want to display a blurry version of the image before the real one loads, include the
LQIP!
- _however, if you want to display a blurry version of the image before the real one loads, include the
- Edit the breakpoint sizes in
constants.tsto match the breakpoints of your project. - There are two hooks included that are useful in other circumstances, see
useInViewport.tsanduseStatefulRef.ts. - You'll need to do a little bit of plumbing to set this up in your project - such as defining an
Imagetype, or swapping outstyled-componentsfor a different styling system that you use. - tip: make the
sizesprop required to ensure you're making these images as small & responsive as possible
A Sanity Tip:
Instead of using Sanity's default image object type in your schema definitions, roll your own and give it a name like richImage. This way you can add additional fields (like alt, caption, or anything else) and those changes will go into effect wherever you use richImage. If you had just used image, you would have to add all of those fields to each instance within your schema! Even if you don't plan on adding additional fields, it's still preferable to set up your own richImage to give you the flexiblity of extending it in the future.
- write some tests
- Make it generic & styling-system agnostic. A simple CSS import should replace styled-components.
- Publish to NPM package
- Remove the
captionrendering, since not all projects will include captions in their images. It will be easy enough to make your own<Image />wrapper component that implements this and renders captions or whatever else.