Working with images in Next.js
Tags: nextjs, react, beginners, codenewbie
Published: 2021-09-18 10:38:04



Rendering images in Next.js for the first time can be frustrating, especially for beginners who are not fond of reading documentation.
 
This article will help you understand how to render images in Next.js, the difference between the `<img>` tag and the `<Image/>` component, and the pitfalls to avoid when working with images in Next.js.  

##How to Render Images in Next.js

There are two ways you can display images in Next.js, you either use the conventional `<img>` tag or a specialized `<Image/>` component that is unique to Next. The differences between these tags are quite much, but they pretty much do the same thing; which is to display images to the browser.

>If you’re rendering images or any media files relatively ( locally ) in your project, you must store them in the `/public` folder directory. Otherwise, you’ll get an error. 

##The `<img>` tag

This is the same HTML `<img>` tag you’re used to, and perhaps the tag you used the first time you rendered an image to the browser.
The tag has no special optimization feature, all it does is link images to a webpage by creating a holding space for the referenced image.

###How to use the `<img>` tag

The `<img>` tag has two important attributes;

* `src`
* `alt`

The `src` attribute takes in a relative or absolute URL path of where the referenced image is located, while the `alt` attribute takes in an alternate text that displays when the image isn’t rendering properly in the browser for some reason. 

Below is a typical example of a `<img>` tag markup:

```javascript
<img src=”/public/dev_logo.png” alt=”dev logo”>
```
You can render images on your Next.js webpage without much hassle with the `<img>` tag, provided the image, if stored locally, is moved to the `/public` folder directory. But the issue of optimization remains.

###Caveats of the `<img>` tag

The `<img>` tag renders images to the webpage with their original size and resolution regardless of the viewport the image is being rendered on.

A quick play around with CSS can fix this, but even with the image displaying precisely to each viewport, the intrinsic size, which is the original size and aspect ratio of the image sent by the server will remain the same.

This is not very efficient, as it will drastically reduce the web page's performance and increase the load time.

To optimize images rendered with the `<img>` tag in your project, you need to implement some extra set of functionalities. some of which are:

-**Lazy loading**: Images will only be fetched and rendered when they are scrolled into the viewport. libraries like “react-lazyload” can easily add this functionality to your project.

-**Resizing**: Detecting and fetching the appropriate image size for every viewport, provided there are images of different sizes stored on the server.

-**Modern image formats**: Conditionally serving stored images with WebP formats when it's supported by the browser.

As you might have noticed, this is a lot of work. If only there was a better way to do this without losing a limb. Oh wait, there is.

##The `<Image/>` component

The `<Image/>` component was contrived by the creators of Next.js to solve the optimization issues the former lacks. It is a better and enhanced version of the `<img>` tag, but unlike the `<img>` tag, the `<Image/>` component is not a native HTML element – but a built-in API in Next.js.

The component essentially wraps the `<img>` element with other div elements to prevent cumulative layout shift.

###Benefits of using the <image/> component

The `<Image/>` component’s API doesn’t just render images to the browser like the `<img>` tag, it also optimizes the image for every viewport by implementing each of the functionalities below out of the box:

-**Lazy loading**: Every image linked to a webpage with the `<Image/>` component is fetched and rendered on-demand as soon as its holding space is scrolled into view by default. So you never have to worry about slow load time on your web pages and writing extra scripts for such functionality.

-**Responsiveness**: Images are automatically responsive when rendered with the `<image/>` component, saving you the stress of CSS media queries. 

-**Resizing**: The appropriate size and aspect ratio of an image for a viewport is fetched and rendered on-demand, instead of fetching the intrinsic size and aspect ratio before reducing it for the target viewport.

-**Optimized file size**: The `<Image/>` component fetches the appropriate file size for each viewport, taking away the need to store images with different file sizes for every viewport on the server, and fetching them one after the other when needed.

-**Optimized image format**: when an image is fetched from the server with the `<Image/>` component, the file format is changed to a more optimized and SEO-friendly one like WebP, if the browser supports it.

###How to use the `<Image/>` component

To use the `<Image/>` component in your Next.js project, the first thing you need to do is import it into your desired component from Next’s library:

```javascript
Import Image from ‘next/image’
```

The next step is to add the JSX syntax to your code with at least an `src`, `width`and `height` property:

```javascript
<Image src={“dev_logo.png”} width={150} height={150} />
```

>N.B If your image is stored locally, it must be located in the `/public` folder, otherwise, you’ll get an error.


The `width` and `height` properties are mandatory, without these properties, Next.js will throw an error.

People, mostly beginners, often mistake these properties for inline styles. Well, that’s exactly what they are, but the image component needs them to perform its magic. They only accept pixels as values, which must also be an integer without a unit.

The component can be served in a project like so:

```javascript
Import Image from ‘next/image’
const Home = () => {
  return (
    <>
      <h1>Homepage</h1>
      <Image src={“hero_image.png”} alt=”Hero image” width={150} height={150}/>
      <p>This is the homepage!</p>
    </>
  )
}
Export default Home
```

Passing the image’s file name into the `src` property is enough for Next to detect and serve the image, as long as the image is in the public folder. You could also import the image statically just as you did the component itself:

```javascript
Import hero from ‘../public/hero_image.png’
```

With the above code added, the new block of code will look like this:

```javascript
Import Image from ‘next/image’
Import hero from ‘../public/hero_image.png’

Const Home = () => {
  Return (
    <>
      <h1>Homepage</h1>
      <Image src={hero} alt=”Hero image” width={150} height={150}/>
      <p>This is the homepage!</p>
    </>
  )
}
Export default Home
```

The only difference here is that the former is being passed dynamically as a path string while the latter, is as a variable.

The `<Image/>` component has other optional properties, some of which are:

`object-fit` : Specifies how an image should be resized to fit its container.

`layout` : The layout behavior of the image as the viewport changes size.

`sizes` : A string mapping media queries to device screen sizes.

`placeholder` : A placeholder to use while the image is loading.

Visit the [docs](https://nextjs.org/docs/api-reference/next/image) for more info. 

###Caveats of the `<Image/>` component


The only major drawback of the `<Image/>` component is its limitations and insusceptibility to CSS styling. The component isn’t immune to styling per se, and since it’s wrapped around an `<img>` element, the possibility of styling isn’t ruled out.

Styling the component isn’t as easy as slamming it a `className` and having a field day in your CSS stylesheet. There are procedures to follow.

The `<image/>` component cannot be styled with a component-scoped stylesheet that doesn’t use Next.js’ built-in CSS support.
  
So if we have a project that has a Homepage component and an embedded `<image/>` component with a `className` of “img”, a scoped CSS stylesheet for our Homepage component will be named like this:

```javascript
Homepage.module.css
```

Adding rules to the “img” class in the Homepage stylesheet will be futile. Now imagine the inevitable frustration awaiting anyone using Next.js for the first time.

The only way you can style `<image/>` components in your project is to;
Create a global stylesheet, add rules to the images’ classes in the global stylesheet, and then importing the global stylesheet within `page/_app.js` as seen in the screenshot below. 

![next global stylesheet code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmhkw27ysjup9cfkilgg.png)

Every page and component in your project will have access to the global stylesheet after the importation.

##How to serve images from external sources in your Next.js project 


Fetching and rendering images from a server, CMS or any external sources in Next.js isn’t as straightforward as passing the URL of the referenced image into the src property. 

Since the `<image/>` component optimizes images automatically, either locally or externally, to prevent abuse on external URLs; you must specify which domains are allowed to be optimized in your project.

This is done by adding an image object with a domain to the `next.config.js` module in your project:

```javascript
module.exports = {
  Images: {
    domains: [‘example.com’],
  },
}
```
##Conclusion
We've seen the differences between the `<img>` tag and the `<Image/>` component, as well as their advantages and disadvantages. Now it's up to you to decide on what to use in your project. And how you could save yourself a lot of time and frustration by avoiding pitfalls like; 

-Trying to style the `<Image/>` component from a non-global stylesheet.
-Not storing local images in the `/public` folder.
-Not specifying the domains of externally linked images.

Complicated as it may look, we've barely grazed the surface of the `<Image/>` component, so for more advanced stuff, please go to the official [documentation](https://nextjs.org/docs/api-reference/next/image).

Follow me on [twitter](twitter.com/ope_motayo) and [linkedin](https://www.linkedin.com/in/david-omotayo-09604a189)