Lens
magicui/lensFreeComponent
A interactive component that enables zooming into images, videos and other elements.
Live preview
live · rendered by the registry
Rendered by magicui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://magicui.design/r/lens.jsonSource
1"use client"23import React, { useCallback, useMemo, useRef, useState } from "react"4import { AnimatePresence, motion, useMotionTemplate } from "motion/react"56interface Position {7 /** The x coordinate of the lens */8 x: number9 /** The y coordinate of the lens */10 y: number11}1213interface LensProps {14 /** The children of the lens */15 children: React.ReactNode16 /** The zoom factor of the lens */17 zoomFactor?: number18 /** The size of the lens */19 lensSize?: number20 /** The position of the lens */21 position?: Position22 /** The default position of the lens */23 defaultPosition?: Position24 /** Whether the lens is static */25 isStatic?: boolean26 /** The duration of the animation */27 duration?: number28 /** The color of the lens */29 lensColor?: string30 /** The aria label of the lens */31 ariaLabel?: string32}3334export function Lens({35 children,36 zoomFactor = 1.3,37 lensSize = 170,38 isStatic = false,39 position = { x: 0, y: 0 },40 defaultPosition,41 duration = 0.1,42 lensColor = "black",43 ariaLabel = "Zoom Area",44}: LensProps) {45 if (zoomFactor < 1) {46 throw new Error("zoomFactor must be greater than 1")47 }48 if (lensSize < 0) {49 throw new Error("lensSize must be greater than 0")50 }5152 const [isHovering, setIsHovering] = useState(false)53 const [mousePosition, setMousePosition] = useState<Position>(position)54 const containerRef = useRef<HTMLDivElement>(null)5556 const currentPosition = useMemo(() => {57 if (isStatic) return position58 if (defaultPosition && !isHovering) return defaultPosition59 return mousePosition60 }, [isStatic, position, defaultPosition, isHovering, mousePosition])6162 const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {63 const rect = e.currentTarget.getBoundingClientRect()64 setMousePosition({65 x: e.clientX - rect.left,66 y: e.clientY - rect.top,67 })68 }, [])6970 const handleKeyDown = useCallback((e: React.KeyboardEvent) => {71 if (e.key === "Escape") setIsHovering(false)72 }, [])7374 const maskImage = useMotionTemplate`radial-gradient(circle ${75 lensSize / 276 }px at ${currentPosition.x}px ${77 currentPosition.y78 }px, ${lensColor} 100%, transparent 100%)`7980 const LensContent = useMemo(() => {81 const { x, y } = currentPosition8283 return (84 <motion.div85 initial={{ opacity: 0, scale: 0.58 }}86 animate={{ opacity: 1, scale: 1 }}87 exit={{ opacity: 0, scale: 0.8 }}88 transition={{ duration }}89// … truncated
What it pulls in
npm packages
Files it writes
More from magicui
All 247 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Androidandroid | magicui | Components | Free | no deps | |
| Animated Beamanimated-beam | magicui | Components | Free | 1 dep | |
| Animated Circular Progress Baranimated-circular-progress-bar | magicui | Components | Free | no deps | |
| Animated Gradient Textanimated-gradient-text | magicui | Components | Free | no deps | |
| Animated Grid Patternanimated-grid-pattern | magicui | Components | Free | 1 dep | |
| Animated Listanimated-list | magicui | Components | Free | 1 dep | |
| Animated Shiny Textanimated-shiny-text | magicui | Components | Free | no deps | |
| Theme Toggleranimated-theme-toggler | magicui | Components | Free | 1 dep |
