Zoom Image to full screen Using React
Published on

Zoom Image to full screen Using React

Authors

This post will explain how you can achieve full-screen zoom for an image whenever a user clicks on it. This is useful if the image has a lot of content and is not clearly visible within our standard website layout. If we allow the user to view the image on full screen, the user can make sense of the full picture.

Suppose you're building your website using React components. In that case, it might be a little challenging to implement HTML zoom solutions available on the internet. I'll be clearly explaining the process of how you can achieve the same. First, let us see the example below. Whenever you hover on the image, you'll get a zoom icon; if you click on it, it will zoom to full screen; you can press Esc or click close button, and then it will exit full screen.

/static/images/posts/2022/react-zoom/example.webp

If this is the similar effect you're looking for, you can directly copy the code below for your react component. Of course, if you're using tailwind as your CSS, you don't have to make changes. Still, if you're using plain CSS, you might have to do some modifications like converting the classNames to CSS.

I use the CSS module so that the CSS is not globally defined and doesn't interfere with my other component CSS. So here I'm describing a few CSS classes which can be used.

image.module.css
.lightbox {
  position: fixed;
  z-index: 999;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;

  background: rgba(0, 0, 0, 0.5);

  display: flex;
  align-items: center;
  align-items: center;

  visibility: hidden;
  opacity: 0;

  transition: opacity ease 0.4s;
}

.show {
  visibility: visible;
  opacity: 1;
}

.show_image {
  width: 100vw;
  height: 100vh;
  object-fit: contain;
}

Your image.jsx should look like below; also, replace the images for magnify.svg and close.svg

image.jsx
import { useState, useCallback, useEffect } from 'react'
import styles from './image.module.css'

const Image = ({ zoom, border, ...rest }) => {
  const escFunction = useCallback((event) => {
    if (event.key === 'Escape') {
      setClick(false)
    }
  }, [])

  useEffect(() => {
    document.addEventListener('keydown', escFunction, false)

    return () => {
      document.removeEventListener('keydown', escFunction, false)
    }
  }, [])

  const [click, setClick] = useState(false)
  const [hovered, setHovered] = useState(false)

  const setFlag = () => {
    setClick(true)
  }

  const unsetFlag = () => {
    setClick(false)
  }

  const onEnter = () => {
    setHovered(true)
  }
  const onExit = () => {
    setHovered(false)
  }

  if (!zoom) return <img {...rest} />
  else
    return (
      <>
        {click ? (
          <div className={`${styles.lightbox} ${styles.show} relative`}>
            <img {...rest} className={`${styles.show_image}`}></img>
            <img
              onClick={unsetFlag}
              className={`absolute right-4 -top-8 h-8 w-8`}
              src="/static/images/icons/close.svg"
            />
          </div>
        ) : (
          <div className="relative" onMouseEnter={onEnter} onMouseLeave={onExit}>
            <img
              {...rest}
              className={`relative ${border && 'p-0.5 rounded bg-gray-700 dark:bg-gray-800'}`}
            ></img>
            {hovered && (
              <img
                onClick={setFlag}
                className={`absolute -bottom-6 left-2 h-8 w-8 p-0.5 rounded bg-gray-700 dark:bg-gray-800`}
                src="/static/images/icons/magnify.svg"
              />
            )}
          </div>
        )}
      </>
    )
}

export default Image

Whenever you want to add an image to any of your pages, you can use the below command border to add a dark border so that the user can differentiate between the image white background from the website background, in case you're website background is also white.

zoom attribute true will enable full zoom capability for your image.

You'll just need to update your path of the image accordingly.

<Image src="REPLACE_PATH_TO_IMAGE" border={true} zoom={true}></Image>

Zoom Image to Fullscreen with React

Below the code is a trimmed-down version of the previous zoom image code. If the user clicks on the image, the picture will become full size, and if the user clicks again, it will move back to normal.

Here we are using useState to store if the user has clicked or not, and based on that, we show div with the image or only image. Most of the magic is present in the CSS rather than the HTML.

import { useState, useCallback, useEffect } from 'react'
import styles from './image.module.css'

const Image = ({ zoom, ...rest }) => {
  const [click, setClick] = useState(false)

  const setFlag = () => {
    setClick(true)
  }

  const unsetFlag = () => {
    setClick(false)
  }

  if (!zoom) return <img {...rest} />
  else
    return (
      <>
        {click ? (
          <div onClick={unsetFlag} className={`${styles.lightbox} ${styles.show} relative`}>
            <img {...rest} className={`${styles.show_image}`}></img>
          </div>
        ) : (
          <img {...rest} onClick={setFlag}></img>
        )}
      </>
    )
}

export default Image

Add overlay image when hovering mouse over Image

Now I'll just explain the code for showing an overlay image when the mouse enters the image and disappears when the mouse leaves the image. We'll have to create state for hover with this command const [hovered, setHovered] = useState(false). Now we can use hovered in our react render function.

You'll also need to create two lambda functions onEnter and onExit, and attach them to div events.

And then, you'll need to set your main image and div as relative and the overlay image as absolute. So that the image moves on top of the base image, which is called an overlay image.

You'll also need to set the position of the overlay image, i.e., top: 0, bottom: 0, etc. I've used tailwind, so I just mention left-0 bottom-0 as className.

import { useState, useCallback, useEffect } from 'react'
import styles from './image.module.css'

const Image = ({ ...rest }) => {
  const [hovered, setHovered] = useState(false)

  const onEnter = () => {
    setHovered(true)
  }
  const onExit = () => {
    setHovered(false)
  }

  return (
    <>
      {
        <div className="relative" onMouseEnter={onEnter} onMouseLeave={onExit}>
          <img {...rest} onClick={setFlag} className={`relative`}></img>
          {hovered && (
            <img className={`absolute left-0 bottom-0`} src="/static/images/icons/magnify.svg" />
          )}
        </div>
      }
    </>
  )
}

export default Image

useEffects for capturing Keyboard events inside Component

Below is the code we can use to capture keyboard events inside our component. With this logic, we had previously used the existing full-screen mode when the user clicks on the escape key on the keyboard.

We can make many helpful keyboard shortcuts for the user with this below design pattern.

import { useEffect } from 'react'
import styles from './image.module.css'

const ExampleComponent = ({}) => {
  const escFunction = useCallback((event) => {
    if (event.key === 'Escape') {
      console.log('Escape Pressed!')
      // Your Custom Logic
    }
  }, [])

  useEffect(() => {
    document.addEventListener('keydown', escFunction, false)

    return () => {
      document.removeEventListener('keydown', escFunction, false)
    }
  }, [])
}

export default ExampleComponent

Conclusion

Let me know if you have any queries in the comments. I'll make sure to answer your questions regarding the same. Creating a zoom box is very easy but we need know a little bit of HTML & CSS and a bit of React also 😀.