Create an Image magnifier with Tailwind CSS
In this post, we’ll explore how to create a dynamic and visually appealing image magnifier using Tailwind CSS. Magnifiers are a common feature in many web applications, especially in e-commerce websites, where users often need to inspect product images in detail. With Tailwind CSS, a utility-first CSS framework, we’ll build an image magnifier that is not only functional but also beautifully styled.
By following this step-by-step guide, you’ll be able to create an image magnifier component with Tailwind CSS that enhances the user experience of your web applications. Tailwind CSS’s utility-first approach and flexibility make it easy to build and customize UI components like image magnifiers, allowing you to create visually stunning and highly functional interfaces with minimal effort. Start experimenting with Tailwind CSS today and take your web development skills to the next level!
First, let us make the component and then explain it.
import React, { useState } from 'react';
const ProductMagnifier = () => {
const magnifierHeight = 100;
const magnifieWidth = 100;
const zoomLevel = 1.5;
const [imgWidth, setImgWidth] = useState(0);
const [imgHeight, setImgHeight] = useState(0);
const [showMagnifier, setShowMagnifier] = useState(false);
const [[x, y], setXY] = useState([0, 0]);
return (
<div className='container mx-auto px-10 lg:px-0 py-10'>
<div className="relative h-full w-full">
<img
src={yourphoto}
className="h-full w-full"
onMouseEnter={(e) => {
const elem = e.currentTarget;
const { width, height } = elem.getBoundingClientRect();
setImgWidth(width);
setImgHeight(height);
setShowMagnifier(true);
}}
onMouseMove={(e) => {
const elem = e.currentTarget;
const { top, left } = elem.getBoundingClientRect();
const x = e.pageX - left - window.pageXOffset;
const y = e.pageY - top - window.pageYOffset;
setXY([x, y]);
}}
onMouseLeave={() => {
setShowMagnifier(false);
}}
alt="img"
/>
{showMagnifier && (
<div
className="absolute pointer-events-none border border-gray-200 bg-white"
style={{
height: `${magnifierHeight}px`,
width: `${magnifieWidth}px`,
top: `${y - magnifierHeight / 2}px`,
left: `${x - magnifieWidth / 2}px`,
backgroundImage: `url('${yourphoto}')`,
backgroundSize: `${imgWidth * zoomLevel}px ${imgHeight * zoomLevel}px`,
backgroundPositionX: `${-x * zoomLevel + magnifieWidth / 2}px`,
backgroundPositionY: `${-y * zoomLevel + magnifierHeight / 2}px`
}}
/>
)}
</div>
</div>
);
};
export default ProductMagnifier;
Explanation:
1. A state that controls the display of magnifier
const [showMagnifier, setShowMagnifier] = useState(false);
2. The event handler that updates the state.
...
<img
src={src}
style={{ height: height, width: width }}
onMouseEnter={(e) => {
setShowMagnifier(true);
}}
onMouseLeave={() => {
setShowMagnifier(false);
}}
alt={"img"}
/>
...
3. Add a state that holds the x and y positions of the magnifier and update it when the mouse moves over the image.
const [[x, y], setXY] = useState([0, 0]);
...
onMouseMove={(e) => {
const elem = e.currentTarget;
const { top, left } = elem.getBoundingClientRect();
const x = e.pageX - left - window.pageXOffset;
const y = e.pageY - top - window.pageYOffset;
setXY([x, y]);
}}
4. The pageX/Y
coordinates are relative to the left/top corner of the current page.
The pageXOffset/pageYOffset
are the page’s scroll offsets.
The left/top coordinates represent the image’s left and top positions.
const x = e.pageX - left - window.pageXOffset;
const y = e.pageY - top - window.pageYOffset;
setXY([x, y]);
5. We can now apply the position and other basic styles to the magnifier.
<div
className="absolute pointer-events-none border border-gray-200 bg-white"
style={{
height: `${magnifierHeight}px`,
width: `${magnifieWidth}px`,
top: `${y - magnifierHeight / 2}px`,
left: `${x - magnifieWidth / 2}px`,
backgroundImage: `url('${yourphoto}')`,
backgroundSize: `${imgWidth * zoomLevel}px ${imgHeight * zoomLevel}px`,
backgroundPositionX: `${-x * zoomLevel + magnifieWidth / 2}px`,
backgroundPositionY: `${-y * zoomLevel + magnifierHeight / 2}px`
}}
/>
That’s it. Thanks for your reading.