Creating a Responsive Image Component in Next.js with TypeScript

In this tutorial, we'll create a ResponsiveImg component that uses the Next.js Image component for optimized image rendering.

 

Introduction

The ResponsiveImg Component
The ResponsiveImg component accepts properties for both mobile and desktop versions of the image. It uses the useEffect and useState hooks to determine the screen size and adjust the image properties accordingly.

Here's the complete code for the ResponsiveImg component:


/**
 * ResponsiveImg component that renders an image which adapts to screen size.
 * It uses the Next.js Image component for optimized image rendering.
 *
 * @component
 * @param {ResponsiveImgProps} props - The properties for the ResponsiveImg component.
 * @param {Object} props.mobile - The properties for the mobile version of the image.
 * @param {string | StaticImport} props.mobile.src - The source of the mobile image.
 * @param {number} props.mobile.width - The width of the mobile image.
 * @param {number} props.mobile.height - The height of the mobile image.
 * @param {Object} props.desktop - The properties for the desktop version of the image.
 * @param {string | StaticImport} props.desktop.src - The source of the desktop image.
 * @param {number} props.desktop.width - The width of the desktop image.
 * @param {number} props.desktop.height - The height of the desktop image.
 * @param {string} props.title - The alt text for the image.
 * @param {string} [props.className] - Additional class names for the image.
 * @param {boolean} [props.isFill=false] - Whether the image should fill its container.
 *
 * @returns {JSX.Element} The rendered ResponsiveImg component.
 *
 * @example
 * <ResponsiveImg
 *   mobile={{ src: '/images/mobile.jpg', width: 300, height: 200 }}
 *   desktop={{ src: '/images/desktop.jpg', width: 600, height: 400 }}
 *   title="Responsive Image"
 *   className="custom-class"
 *   isFill={false}
 * />
 */
"use client";
import Image from "next/image";
import { useEffect, useState } from "react";
import { ResponsiveImgProps } from "@/interfaces/basic";
import { StaticImport } from "next/dist/shared/lib/get-img-props";

const ResponsiveImg: React.FC<ResponsiveImgProps> = (props) => {
  const [isSmallScreen, setIsSmallScreen] = useState(false);

  useEffect(() => {
    if (typeof window !== 'undefined') {
      setIsSmallScreen(window.innerWidth < 768);

      const handleResize = () => {
        setIsSmallScreen(window.innerWidth < 768);
      };

      window.addEventListener("resize", handleResize);

      return () => {
        window.removeEventListener("resize", handleResize);
      };
    }
  }, []);

  const imgProps: Omit<React.ComponentProps<typeof Image>, "src"> & {
    src: string | StaticImport;
  } = {
    src: (isSmallScreen ? props.mobile.src : props.desktop.src) as string,
    alt: props.title,
    className: props.className + (props.isFill ? " important-relative" : ""),
    width: props.isFill
      ? undefined
      : isSmallScreen
      ? props.mobile.width
      : props.desktop.width,
    height: props.isFill
      ? undefined
      : isSmallScreen
      ? props.mobile.height
      : props.desktop.height,
    layout: props.isFill ? "fill" : undefined,
    style: props.isFill ? { objectFit: "contain" } : undefined,
  };
  return (
    <>
      <Image {...imgProps} />
    </>
  );
};


The typescript interface :

export interface ResponsiveImgProps {
    title: string;
    className?: string;
    isFill?: boolean;
    mobile: { width?: number; height?: number; src: string  |
import("next/dist/shared/lib/get-img-props").StaticImport;};
    desktop: { width?: number; height?: number; src: string  |
import("next/dist/shared/lib/get-img-props").StaticImport;};
  }
 


Example Usage

Let's see how we can use the ResponsiveImg component in different parts of our application.

Example 1: 100%


  <ResponsiveImg
  title="img 100%"
  className="h-48 w-full object-cover md:h-full md:w-48 justify-center"
  isFill={true}
  mobile={{
    src: "/images/mobile.png",
  }}
  desktop={{
    src: "/images/desktop.png",
  }}
/>


Example 2: sizes


<ResponsiveImg
  title="change img size"
  className="inline-block"
  mobile={{
    width: 110,
    height: 20,
    src: "/images/master/negevMobileFooter.png",
  }}
  desktop={{
    width: 280,
    height: 60,
    src: "/images/master/footerNegevIcon.png",
  }}
/>


Conclusion

In this post, we've created a ResponsiveImg component that adapts to different screen sizes by changing the image source and dimensions. This component leverages the power of Next.js and TypeScript to provide optimized and type-safe image rendering.

Feel free to use and modify this component in your projects to enhance the responsiveness of your web applications.

Happy coding!
Roi

Comments

Popular posts from this blog

A sharepoint list view of the current month

The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters

Export SharePoint 2010 List to Excel with PowerShell