Back to Heroui

Image

apps/docs/content/docs/react/migration/(components)/image.mdx

3.0.412.6 KB
Original Source
<Callout type="warning"> The Image component has been **removed** in HeroUI v3. Use native HTML `` element or Next.js `Image` component with Tailwind CSS classes instead. </Callout>

Key Changes

1. Component Removal

v2: <Image> component from @heroui/react
v3: Native HTML `` element or Next.js Image component

2. Features Mapping

The v2 Image component had several features that need to be replaced:

v2 Featurev3 EquivalentNotes
radius proprounded-* Tailwind classesUse rounded-sm, rounded-md, rounded-lg, rounded-full
shadow propshadow-* Tailwind classesUse shadow-sm, shadow-md, shadow-lg
isBlurred propManual blur implementationUse CSS filter: blur() or Tailwind blur-* utilities
isZoomed propManual hover zoomUse hover:scale-* Tailwind classes
fallbackSrc propManual error handlingUse onError handler with state
disableSkeleton / Loading skeletonManual loading stateUse React state + conditional rendering
removeWrapper propDirect renderingNo wrapper needed, render `` directly

Structure Changes

In v2, Image was a component wrapper around the native `` element:

tsx
import { Image } from "@heroui/react";

export default function App() {
  return (
    <Image
      src="https://example.com/image.jpg"
      alt="Example image"
      width={300}
      height={200}
    />
  );
}

In v3, use the native `` element directly with Tailwind CSS classes:

tsx
export default function App() {
  return (
    
  );
}

Migration Examples

If you're using Next.js, use the optimized Image component:

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { Image } from "@heroui/react";

<Image
  src="/image.jpg"
  alt="Example"
  width={300}
  height={200}
/>
```
</Tab> <Tab value="v3"> ```tsx import Image from "next/image";
<Image
  src="/image.jpg"
  alt="Example"
  width={300}
  height={200}
  className="rounded-lg"
/>
```
</Tab> </Tabs>

With Zoom Effect

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Image isZoomed src="..." alt="..." /> </Tab> <Tab value="v3"> ```tsx <div className="relative overflow-hidden rounded-lg">

</div>
```
</Tab> </Tabs>

With Blur Effect

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Image isBlurred src="..." alt="..." /> </Tab> <Tab value="v3"> ```tsx <div className="relative">

</div>
```
</Tab> </Tabs>

With Fallback Image

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Image src="https://example.com/image.jpg" fallbackSrc="/fallback.jpg" alt="Example" /> </Tab> <Tab value="v3"> ```tsx import { useState } from "react";

function ImageWithFallback({ src, fallbackSrc, alt, ...props }) {
  const [imgSrc, setImgSrc] = useState(src);

  return (
     setImgSrc(fallbackSrc)}
      {...props}
    />
  );
}

<ImageWithFallback
  src="https://example.com/image.jpg"
  fallbackSrc="/fallback.jpg"
  alt="Example"
/>
```
</Tab> </Tabs>

With Loading Skeleton

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Image src="https://example.com/image.jpg" alt="Example" disableSkeleton={false} /> </Tab> <Tab value="v3"> ```tsx 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" />
      )}
       setIsLoading(false)}
        onError={() => {
          setIsLoading(false);
          setHasError(true);
        }}
        {...props}
      />
    </div>
  );
}

<ImageWithSkeleton src="https://example.com/image.jpg" alt="Example" />
```
</Tab> </Tabs>

Combined Features

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Image src="https://example.com/image.jpg" alt="Example" radius="lg" shadow="md" isZoomed isBlurred width={400} height={300} /> </Tab> <Tab value="v3"> ```tsx <div className="relative overflow-hidden rounded-lg shadow-md">

</div>
```
</Tab> </Tabs>

Creating a Reusable Image Component (Optional)

If you frequently use images with similar features, you can create a reusable component:

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { Image } from "@heroui/react";

<Image
  src="..."
  radius="lg"
  shadow="md"
  isZoomed
/>
```
</Tab> <Tab value="v3"> ```tsx 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 = (
     setIsLoading(false)}
      onError={handleError}
      {...props}
    />
  );

  if (isBlurred) {
    return (
      <div className={cn("relative", radiusClasses[radius], shadowClasses[shadow])}>
        {imageElement}
        
      </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"
/>
```
</Tab> </Tabs>

Complete Example

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx 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>
  );
}
```
</Tab> <Tab value="v3"> ```tsx export default function App() { return ( <div className="space-y-4">
      <div className="relative overflow-hidden rounded-lg">
        
      </div>
      <div className="relative rounded-full">
        
        
      </div>
    </div>
  );
}
```
</Tab> </Tabs>

Summary

  1. Component Removed: Image component no longer exists in v3
  2. Import Change: Remove import { Image } from "@heroui/react"
  3. Use Native Element: Replace with native `` HTML element or Next.js Image
  4. Features: Implement blur, zoom, skeleton, and fallback manually
  5. Styling: Apply Tailwind CSS classes directly for radius, shadow, and effects

Migration Steps

  1. Remove Import: Remove Image from @heroui/react imports
  2. Replace Component: Replace all <Image> instances with `` elements
  3. Add Tailwind Classes: Apply equivalent Tailwind classes for styling (radius, shadow)
  4. Implement Features: Add manual implementations for blur, zoom, skeleton, and fallback if needed
  5. Use Next.js Image: If using Next.js, consider using next/image for optimization
  6. Optional: Create reusable wrapper components for frequently used patterns

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
tsx
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
/>