Image
Migration guide for Image from HeroUI v2 to v3
The Image component has been removed in HeroUI v3. Use native HTML <img> element or Next.js Image component with Tailwind CSS classes instead.
Overview
The Image component was a feature-rich wrapper around the native HTML <img> element with built-in support for blur effects, zoom animations, loading skeletons, and fallback images. In v3, you should use native <img> elements (or Next.js Image for optimization) and implement these features manually with Tailwind CSS and React hooks.
Key Changes
1. Component Removal
v2: <Image> component from @heroui/react
v3: Native HTML <img> element or Next.js Image component
2. Features Mapping
The v2 Image component had several features that need to be replaced:
| v2 Feature | v3 Equivalent | Notes |
|---|---|---|
radius prop | rounded-* Tailwind classes | Use rounded-sm, rounded-md, rounded-lg, rounded-full |
shadow prop | shadow-* Tailwind classes | Use shadow-sm, shadow-md, shadow-lg |
isBlurred prop | Manual blur implementation | Use CSS filter: blur() or Tailwind blur-* utilities |
isZoomed prop | Manual hover zoom | Use hover:scale-* Tailwind classes |
fallbackSrc prop | Manual error handling | Use onError handler with state |
disableSkeleton / Loading skeleton | Manual loading state | Use React state + conditional rendering |
removeWrapper prop | Direct rendering | No wrapper needed, render <img> directly |
Migration Examples
Basic Usage
import { Image } from "@heroui/react";
export default function App() {
return (
<Image
src="https://example.com/image.jpg"
alt="Example image"
width={300}
height={200}
/>
);
}export default function App() {
return (
<img
src="https://example.com/image.jpg"
alt="Example image"
width={300}
height={200}
className="rounded-lg"
/>
);
}With Next.js Image (Recommended)
If you're using Next.js, use the optimized Image component:
import { Image } from "@heroui/react";
<Image
src="/image.jpg"
alt="Example"
width={300}
height={200}
/>import Image from "next/image";
<Image
src="/image.jpg"
alt="Example"
width={300}
height={200}
className="rounded-lg"
/>With Radius Variants
<Image radius="sm" src="..." alt="..." />
<Image radius="md" src="..." alt="..." />
<Image radius="lg" src="..." alt="..." />
<Image radius="full" src="..." alt="..." /><img src="..." alt="..." className="rounded-sm" />
<img src="..." alt="..." className="rounded-md" />
<img src="..." alt="..." className="rounded-lg" />
<img src="..." alt="..." className="rounded-full" />With Shadow Variants
<Image shadow="sm" src="..." alt="..." />
<Image shadow="md" src="..." alt="..." />
<Image shadow="lg" src="..." alt="..." /><img src="..." alt="..." className="shadow-sm" />
<img src="..." alt="..." className="shadow-md" />
<img src="..." alt="..." className="shadow-lg" />With Zoom Effect
<Image isZoomed src="..." alt="..." /><div className="relative overflow-hidden rounded-lg">
<img
src="..."
alt="..."
className="object-cover transition-transform duration-300 hover:scale-125"
/>
</div>With Blur Effect
<Image isBlurred src="..." alt="..." /><div className="relative">
<img
src="..."
alt="..."
className="relative z-10"
/>
<img
src="..."
alt=""
aria-hidden="true"
className="absolute inset-0 z-0 h-full w-full scale-105 object-cover blur-lg opacity-30 saturate-150"
/>
</div>With Fallback Image
<Image
src="https://example.com/image.jpg"
fallbackSrc="/fallback.jpg"
alt="Example"
/>import { useState } from "react";
function ImageWithFallback({ src, fallbackSrc, alt, ...props }) {
const [imgSrc, setImgSrc] = useState(src);
return (
<img
src={imgSrc}
alt={alt}
onError={() => setImgSrc(fallbackSrc)}
{...props}
/>
);
}
<ImageWithFallback
src="https://example.com/image.jpg"
fallbackSrc="/fallback.jpg"
alt="Example"
/>With Loading Skeleton
<Image
src="https://example.com/image.jpg"
alt="Example"
disableSkeleton={false}
/>import { useState } from "react";
function ImageWithSkeleton({ src, alt, ...props }) {
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);
return (
<div className="relative overflow-hidden rounded-lg bg-default-200">
{isLoading && (
<div className="absolute inset-0 animate-pulse bg-gradient-to-r from-transparent via-default-300 to-transparent" />
)}
<img
src={src}
alt={alt}
className={`transition-opacity duration-300 ${
isLoading ? "opacity-0" : "opacity-100"
}`}
onLoad={() => setIsLoading(false)}
onError={() => {
setIsLoading(false);
setHasError(true);
}}
{...props}
/>
</div>
);
}
<ImageWithSkeleton src="https://example.com/image.jpg" alt="Example" />Combined Features
<Image
src="https://example.com/image.jpg"
alt="Example"
radius="lg"
shadow="md"
isZoomed
isBlurred
width={400}
height={300}
/><div className="relative overflow-hidden rounded-lg shadow-md">
<img
src="https://example.com/image.jpg"
alt="Example"
width={400}
height={300}
className="relative z-10 object-cover transition-transform duration-300 hover:scale-125"
/>
<img
src="https://example.com/image.jpg"
alt=""
aria-hidden="true"
className="absolute inset-0 z-0 h-full w-full scale-105 object-cover blur-lg opacity-30 saturate-150"
/>
</div>Creating a Reusable Image Component (Optional)
If you frequently use images with similar features, you can create a reusable component:
import { Image } from "@heroui/react";
<Image
src="..."
radius="lg"
shadow="md"
isZoomed
/>import { useState } from "react";
import { cn } from "@/lib/utils"; // or your cn utility
interface CustomImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
radius?: "none" | "sm" | "md" | "lg" | "full";
shadow?: "none" | "sm" | "md" | "lg";
isZoomed?: boolean;
isBlurred?: boolean;
fallbackSrc?: string;
}
const radiusClasses = {
none: "rounded-none",
sm: "rounded-sm",
md: "rounded-md",
lg: "rounded-lg",
full: "rounded-full",
};
const shadowClasses = {
none: "shadow-none",
sm: "shadow-sm",
md: "shadow-md",
lg: "shadow-lg",
};
export function CustomImage({
src,
alt,
className,
radius = "lg",
shadow = "none",
isZoomed = false,
isBlurred = false,
fallbackSrc,
onError,
...props
}: CustomImageProps) {
const [imgSrc, setImgSrc] = useState(src);
const [isLoading, setIsLoading] = useState(true);
const handleError = (e: React.SyntheticEvent<HTMLImageElement, Event>) => {
if (fallbackSrc && imgSrc !== fallbackSrc) {
setImgSrc(fallbackSrc);
}
onError?.(e);
};
const imageElement = (
<img
src={imgSrc}
alt={alt}
className={cn(
radiusClasses[radius],
shadowClasses[shadow],
isZoomed && "object-cover transition-transform duration-300 hover:scale-125",
isLoading && "opacity-0",
"transition-opacity duration-300",
className
)}
onLoad={() => setIsLoading(false)}
onError={handleError}
{...props}
/>
);
if (isBlurred) {
return (
<div className={cn("relative", radiusClasses[radius], shadowClasses[shadow])}>
{imageElement}
<img
src={imgSrc}
alt=""
aria-hidden="true"
className={cn(
"absolute inset-0 z-0 h-full w-full scale-105 object-cover blur-lg opacity-30 saturate-150",
radiusClasses[radius]
)}
/>
</div>
);
}
if (isZoomed || isLoading) {
return (
<div className={cn("relative overflow-hidden", radiusClasses[radius], shadowClasses[shadow])}>
{isLoading && (
<div className="absolute inset-0 animate-pulse bg-gradient-to-r from-transparent via-default-300 to-transparent" />
)}
{imageElement}
</div>
);
}
return imageElement;
}
// Usage
<CustomImage
src="..."
alt="Example"
radius="lg"
shadow="md"
isZoomed
isBlurred
fallbackSrc="/fallback.jpg"
/>Complete Example
import { Image } from "@heroui/react";
export default function App() {
return (
<div className="space-y-4">
<Image
src="https://example.com/image1.jpg"
alt="Image 1"
width={300}
height={200}
radius="lg"
shadow="md"
/>
<Image
src="https://example.com/image2.jpg"
alt="Image 2"
width={300}
height={200}
isZoomed
radius="lg"
/>
<Image
src="https://example.com/image3.jpg"
alt="Image 3"
width={300}
height={200}
isBlurred
radius="full"
/>
</div>
);
}export default function App() {
return (
<div className="space-y-4">
<img
src="https://example.com/image1.jpg"
alt="Image 1"
width={300}
height={200}
className="rounded-lg shadow-md"
/>
<div className="relative overflow-hidden rounded-lg">
<img
src="https://example.com/image2.jpg"
alt="Image 2"
width={300}
height={200}
className="object-cover transition-transform duration-300 hover:scale-125"
/>
</div>
<div className="relative rounded-full">
<img
src="https://example.com/image3.jpg"
alt="Image 3"
width={300}
height={300}
className="relative z-10 rounded-full"
/>
<img
src="https://example.com/image3.jpg"
alt=""
aria-hidden="true"
className="absolute inset-0 z-0 h-full w-full scale-105 object-cover rounded-full blur-lg opacity-30 saturate-150"
/>
</div>
</div>
);
}Breaking Changes Summary
- Component Removed:
Imagecomponent no longer exists in v3 - Import Change: Remove
import { Image } from "@heroui/react" - Use Native Element: Replace with native
<img>HTML element or Next.jsImage - Features: Implement blur, zoom, skeleton, and fallback manually
- Styling: Apply Tailwind CSS classes directly for radius, shadow, and effects
Migration Steps
- Remove Import: Remove
Imagefrom@heroui/reactimports - Replace Component: Replace all
<Image>instances with<img>elements - Add Tailwind Classes: Apply equivalent Tailwind classes for styling (radius, shadow)
- Implement Features: Add manual implementations for blur, zoom, skeleton, and fallback if needed
- Use Next.js Image: If using Next.js, consider using
next/imagefor optimization - Optional: Create reusable wrapper components for frequently used patterns
Tips for Migration
- Next.js Users: Use
next/imagefor automatic optimization, lazy loading, and responsive images - Simple Images: For basic images, native
<img>with Tailwind classes is sufficient - Complex Features: Create custom hooks or components for blur, zoom, and loading states
- Performance: Use
loading="lazy"attribute for images below the fold - Accessibility: Always include
alttext and consideraria-hidden="true"for decorative blurred backgrounds - Error Handling: Implement
onErrorhandlers for fallback images - Loading States: Use React state to manage loading and error states
Next.js Image Component
If you're using Next.js, the Image component from next/image provides:
- Automatic image optimization
- Lazy loading by default
- Responsive images with
srcSet - Placeholder blur support
- Built-in loading states
import Image from "next/image";
<Image
src="/image.jpg"
alt="Example"
width={300}
height={200}
className="rounded-lg shadow-md"
placeholder="blur" // Optional: blur placeholder
blurDataURL="data:image/..." // Optional: base64 blur data
/>Need Help?
For styling guidance:
- See the Styling documentation
- Check Tailwind CSS documentation for utility classes
For Next.js Image:
For community support: