Image Component

The image component has a lot of baked-in performance and accessibility benefits, and should be used over a normal <img /> element wherever possible.

Lazy Loading

Image includes automatic lazy loading. This means that images that are not in the user's viewport will not be loaded. Instead, a low-quality placeholder (LQIP) version of the full-size image will be displayed until the user scrolls the image in to view. Once the image is in view, the full-size image will begin to download, and then it will replace the LQIP.

The sizes prop

We use an image sizing method that can deliver cropped images on the fly by passing width and height parameters to the URL. The Image component takes the given src and your sizes values and creates a map of URLs, one for each breakpoint in your theme. For example, if your theme has 5 breakpoints, if you supply 5 values to sizes, each value will map to one breakpoint. The values can be either pixel values, or fractions of the viewport width.

For the example, image that your theme contains the following breakpoints: [20rem, 40rem, 60rem, 100rem]

and you pass the following sizes array: [1, 1/2, 1/4, 200]

This indicates that for your smallest breakpoint (20rem), you want to use an image with a resolution that matches the viewport resolution (1 will be converted to 100vw, meaning 100% of the viewport). So, this will create an image that is 320px wide (that is 20rem in pixels). It will also create an image that is 640px wide, to account for 2x DPI displays.

Since 1/2 is given for the second value, that indicates that at the 40rem breakpoint, you want an image that is half the size of the viewport. So, that would create 2 images: (40 * 1/2) * 16) and (40 * 1/2) * 16 * 2) for the 2x DPI version. Again, that would create one 320px wide image and one 640px image.

Hopefully you're getting an idea of how this works now! The next provided value is 1/4 and the breakpoint is 60rem. (60 * 1/4) * 16) === 240. So a 240px and 480px image would be generated for that breakpoint.

Finally, the last value in the sizes array is 200. This is assumed to be a px value (any value over 2 is assumed to be given in pixels). So for the largest breakpoint, a 200px and a 400px image will be generated.

So, now we know exactly what size image to render at each breakpoint. This is passed to the srcSet, and the browser will handle loading the correct image based on the user's viewport and DPI.

For more info on how srcSet works, check out https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-srcset

Note

Once the browser has decided which image is the correct size for the current viewport, we take that URL and set it as the background image of a div, and hide the actual img. We do this so that it's easier to overlay the image with text or other elements (by including them as children of the Image component), and also to enable the cover prop to employ background-size: cover.

Setting the displayed width of your image

All of the above refers to the natural resolution of the image that will be loaded. To make the image responsive, it will be set to fill 100% of its container. If you want to restrict the width of the image on-screen, wrap it in a container and give that container a width.

For example, if you passed 1/2 for the 40rem breakpoint, you may want to wrap the image in a container to ensure it fills a maximum of 50% of the viewport at the 40rem breakpoint (otherwise the image will look pixelated).

Usage

Copy
Copied
<Playground>
  <Image
    src="https://demostore.dev.jetshop.se/pub_images/original/224133.jpg"
    sizes={[1 / 5, 1 / 2, 1]}
    aspect="16:9"
    alt="A bike"
  />
</Playground>

Aspect

The aspect prop is used to define the aspect ratio of your image. You can see this in action by expanding the demo above and changing the aspect value.

By using the aspect prop, your image will be resized to fit your desired aspect ratio. By default your image will not be cropped, but you can opt-in to cropping if you like.

Quality

By default, all images will be slightly compressed to optimise their filesize. The Image component accepts a quality prop, which may be set to a number between 1-100. The default setting is 80.

Cropping

If you would like your image to be cropped to your specified aspect ratio, you can pass the prop crop={true}. This may be useful in cases where it's not necessary to show the entire image (such as for banner images), and can save data transfer by reducing the size of the displayed image.

Gravity

'north' | 'south' | 'west' | 'east' | 'centre' | 'smart'

When cropping an image, you may specify a 'gravity', which refers to the image region you want to crop to. north will crop to the top of the image, west to the left, and so on.

smart will attempt to find the "most interesting" part of the image, and will crop in to that region.

Copy
Copied
<Playground>
  <h2>Crop set to south</h2>
  <Image
    src="https://demostore.dev.jetshop.se/pub_images/original/224133.jpg"
    sizes={[1 / 5, 1 / 2, 1]}
    crop
    gravity="south"
    aspect="21:9"
    alt="A bike"
  />
</Playground>

Fill available space

Sometimes you just want the image to fill the space available in the layout. This can be especially useful for banner images, for example.

To make this easier, you can apply the prop fillAvailableSpace={true}. This will force the image to fill its container by setting the height to 100% and setting the background-size to cover.

Try using fillAvailableSpace along with crop, aspect, and gravity to optimise the size and positioning of your final image.

Note that you will need a container around your image in order to define the height.

Copy
Copied
<Playground>
  <>
    <small>
      fillAvailableSpace, gravity="smart", crop — inside a wrapper with 100px
      height
    </small>
    <div style={{ marginTop: "1em", height: 100 }}>
      <Image
        src="https://demostore.dev.jetshop.se/pub_images/original/224133.jpg"
        sizes={[1 / 5, 1 / 2, 1]}
        crop
        fillAvailableSpace
        gravity="smart"
        alt="A bike"
      />
    </div>
  </>
</Playground>

Critical

By setting the critical prop to true, a LQIP will not be generated and the image will instead load immediately. This is especially useful for hero images and other images that are part of the "critical" page load - meaning those that are displayed above-the-fold when a user first visits a page.

It's recommended that this is used on category images for example, as these are often the largest image on the page, and loading them with critical will improve Google's Largest Contentful Paint score (see https://web.dev/lcp/ for more detail on LCP).

Styling images

For the most part, you should not need to style the Image component. If you find yourself manually changing the height, padding, or background-size, you probably want to use the props described above instead.

However, there are some data attributes applied to images that you can use in your CSS to style them if you need to.

[data-flight-image-root]

This is applied to all image components. You can target it in your CSS like this:

Copy
Copied
[data-flight-image-root] {
  border: 1px solid pink;
}

[data-flight-image-loaded='true'] or [data-flight-image-loaded='false']

This will be false when the image is still loading or has an error, otherwise it will be true. You can target it in your CSS like this:

Copy
Copied
[data-flight-image-loaded="true"] {
  border: 1px solid green;
}
[data-flight-image-loaded="false"] {
  border: 1px solid red;
}

[data-flight-image-error='true'] or [data-flight-image-error='false']

This will be false when there is no error, and true when there is.

Copy
Copied
[data-flight-image-error="true"] {
  border: 1px solid red;
}
[data-flight-image-error="false"] {
  border: 1px solid green;
}

Broken and failed images

Broken/failed images will display an error message at the same aspect ratio and size as the image would have been, so the page layout will be maintained.

You can customise the error message using the error prop.

Example with default error:

Copy
Copied
<Playground>
  <Image src="http://example.com/broken-image.jpg" aspect="10:1" />
</Playground>

Example with custom error:

space that the original image would have been.

Copy
Copied
<Playground>
  <Image
    src="http://example.com/broken-image.jpg"
    aspect="10:1"
    error={() => (
      <div style={{ background: "salmon", color: "pink", textAlign: "center" }}>
        This image does not exist!
      </div>
    )}
  />
</Playground>
Copyright © Norce 2023. All right reserved.