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
srcSet
s - 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
sizes
attribute without having to type in your media queries. - Lighthouse benefits:
- Images are properly sized and use
webp
when available - Lazy-loaded images mean faster load times
- The
RatioPadding
component 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/image
component takes care of (most) of this on its own, you don't need to use any of this!- Oops! Actually,
next/image
only does this for statically imported images, i.e. images that are in yourpublic
directory.
- Oops! Actually,
- To get the aspect ratio, be sure to include the asset's
metadata
in your Groq query. _To reduce network request payloads, be sure to request onlymetadata.dimensions
. Sanity image metadata also includes a fairly largepalette
object, 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.ts
to match the breakpoints of your project. - There are two hooks included that are useful in other circumstances, see
useInViewport.ts
anduseStatefulRef.ts
. - You'll need to do a little bit of plumbing to set this up in your project - such as defining an
Image
type, or swapping outstyled-components
for a different styling system that you use. - tip: make the
sizes
prop 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
caption
rendering, 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.