Overview

Image is a widget that displays an image.

The Image widget loads and displays images from network, local files, or assets. It supports various image formats and provides sizing and positioning options. You can control how the image fits into the allocated space using the objectFit property.

When to use it?

  • When displaying images in your app
  • When showing thumbnails or profile pictures
  • When displaying background images or illustrations
  • When actual images are needed instead of icons
  • When responsive image layouts are required

Basic Usage

// Basic image
Image({
  src: 'https://example.com/image.jpg'
})

// Image with specified size
Image({
  src: '/assets/profile.png',
  width: 100,
  height: 100
})

// Image with fit options
Image({
  src: '/assets/banner.jpg',
  width: 300,
  height: 200,
  objectFit: 'cover',
  objectPosition: 'center'
})

Props

src (required)

Value: string

The URL or path of the image to display.

Image({
  src: 'https://example.com/photo.jpg'  // Network image
})

Image({
  src: '/images/logo.png'  // Local image
})

width

Value: number | undefined

The width of the image in pixels.

Image({
  src: '/image.jpg',
  width: 200
})

height

Value: number | undefined

The height of the image in pixels.

Image({
  src: '/image.jpg',
  height: 150
})

objectFit

Value: ObjectFit | undefined

Determines how the image should be resized to fit the specified dimensions.

Available values:

  • 'fill': Stretches the image to fill the entire area (default)
  • 'contain': Maintains aspect ratio and fits within the area
  • 'cover': Maintains aspect ratio and covers the entire area
  • 'none': Maintains original size
  • 'scale-down': Chooses the smaller of none or contain
Image({
  src: '/banner.jpg',
  width: 300,
  height: 200,
  objectFit: 'cover'  // Maintain ratio and fill area
})

objectPosition

Value: ObjectPosition | undefined

Specifies the position of the image.

Available values:

  • 'center': Center (default)
  • 'top': Top
  • 'right': Right
  • 'bottom': Bottom
  • 'left': Left
  • 'top left': Top left
  • 'top right': Top right
  • 'bottom left': Bottom left
  • 'bottom right': Bottom right
Image({
  src: '/photo.jpg',
  width: 200,
  height: 200,
  objectFit: 'cover',
  objectPosition: 'top'  // Show top portion
})

Practical Examples

Example 1: Profile Image

const ProfileImage = ({ imageUrl, name, size = 80 }) => {
  return Container({
    width: size,
    height: size,
    decoration: BoxDecoration({
      borderRadius: BorderRadius.circular(size / 2),
      border: Border.all({ color: '#E0E0E0', width: 2 })
    }),
    clipped: true,
    child: imageUrl ? 
      Image({
        src: imageUrl,
        width: size,
        height: size,
        objectFit: 'cover',
        objectPosition: 'center'
      }) :
      Container({
        color: '#F0F0F0',
        child: Center({
          child: Text(name.charAt(0).toUpperCase(), {
            style: TextStyle({
              fontSize: size / 2,
              fontWeight: 'bold',
              color: '#666'
            })
          })
        })
      })
  });
};

Example 2: Product Card

const ProductCard = ({ product }) => {
  return Container({
    decoration: BoxDecoration({
      color: 'white',
      borderRadius: BorderRadius.circular(12),
      boxShadow: [
        BoxShadow({
          color: 'rgba(0, 0, 0, 0.1)',
          blurRadius: 8,
          offset: { x: 0, y: 2 }
        })
      ]
    }),
    clipped: true,
    child: Column({
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        AspectRatio({
          aspectRatio: 4 / 3,
          child: Image({
            src: product.imageUrl,
            objectFit: 'cover'
          })
        }),
        Padding({
          padding: EdgeInsets.all(16),
          child: Column({
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(product.name, {
                style: TextStyle({
                  fontSize: 18,
                  fontWeight: 'bold'
                })
              }),
              SizedBox({ height: 8 }),
              Text(`$${product.price.toFixed(2)}`, {
                style: TextStyle({
                  fontSize: 20,
                  color: '#FF5733',
                  fontWeight: 'bold'
                })
              })
            ]
          })
        })
      ]
    })
  });
};
const GalleryItem = ({ imageUrl, title, onTap }) => {
  const [isHovered, setIsHovered] = useState(false);

  return GestureDetector({
    onTap: onTap,
    onMouseEnter: () => setIsHovered(true),
    onMouseLeave: () => setIsHovered(false),
    child: Container({
      decoration: BoxDecoration({
        borderRadius: BorderRadius.circular(8),
        boxShadow: isHovered ? [
          BoxShadow({
            color: 'rgba(0, 0, 0, 0.2)',
            blurRadius: 12,
            offset: { x: 0, y: 6 }
          })
        ] : []
      }),
      clipped: true,
      child: Stack({
        children: [
          Image({
            src: imageUrl,
            width: 300,
            height: 200,
            objectFit: 'cover'
          }),
          if (isHovered) Positioned({
            bottom: 0,
            left: 0,
            right: 0,
            child: Container({
              padding: EdgeInsets.all(12),
              decoration: BoxDecoration({
                gradient: LinearGradient({
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, 0.7)']
                })
              }),
              child: Text(title, {
                style: TextStyle({
                  color: 'white',
                  fontSize: 16,
                  fontWeight: 'bold'
                })
              })
            })
          })
        ]
      })
    })
  });
};

Example 4: Hero Header with Background

const HeroHeader = ({ backgroundImage, title, subtitle }) => {
  return Container({
    height: 400,
    child: Stack({
      fit: StackFit.expand,
      children: [
        Image({
          src: backgroundImage,
          objectFit: 'cover',
          objectPosition: 'center'
        }),
        Container({
          decoration: BoxDecoration({
            gradient: LinearGradient({
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: [
                'rgba(0, 0, 0, 0.3)',
                'rgba(0, 0, 0, 0.7)'
              ]
            })
          })
        }),
        Center({
          child: Column({
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(title, {
                style: TextStyle({
                  fontSize: 48,
                  fontWeight: 'bold',
                  color: 'white'
                })
              }),
              SizedBox({ height: 16 }),
              Text(subtitle, {
                style: TextStyle({
                  fontSize: 20,
                  color: 'rgba(255, 255, 255, 0.9)'
                })
              })
            ]
          })
        })
      ]
    })
  });
};

Example 5: Thumbnail List

const ThumbnailList = ({ images, selectedIndex, onSelect }) => {
  return Container({
    height: 80,
    child: Row({
      children: images.map((image, index) => 
        GestureDetector({
          onTap: () => onSelect(index),
          child: Container({
            width: 80,
            height: 80,
            margin: EdgeInsets.only({ right: 8 }),
            decoration: BoxDecoration({
              borderRadius: BorderRadius.circular(8),
              border: Border.all({
                color: index === selectedIndex ? '#2196F3' : '#E0E0E0',
                width: index === selectedIndex ? 3 : 1
              })
            }),
            clipped: true,
            child: Opacity({
              opacity: index === selectedIndex ? 1 : 0.7,
              child: Image({
                src: image.thumbnailUrl,
                width: 80,
                height: 80,
                objectFit: 'cover'
              })
            })
          })
        })
      )
    })
  });
};

Loading State Handling

The Image widget displays an empty space of the specified size while the image is loading. To show a loading indicator, separate state management is required:

const ImageWithLoader = ({ src, width, height }) => {
  const [isLoading, setIsLoading] = useState(true);

  return Stack({
    children: [
      Image({
        src,
        width,
        height,
        objectFit: 'cover'
      }),
      if (isLoading) Center({
        child: CircularProgressIndicator()
      })
    ]
  });
};

Performance Considerations

  1. Image size: Use appropriately sized images for display
  2. Format selection: Consider efficient formats like WebP
  3. Lazy loading: Load only visible images in scroll areas
  4. Caching: Utilize browser caching

Important Notes

  • If neither width nor height is specified, the original image size is used
  • objectFit and objectPosition only take effect when image dimensions are specified
  • Network images may be affected by CORS policies
  • Some features may be limited in SVG rendering mode
  • Container: When additional styling is needed for images
  • ClipRRect: To clip images with rounded corners
  • AspectRatio: To maintain image aspect ratio
  • FadeInImage: When fade-in effect is needed