Skip to content

Image

The Image component provides a robust way to display images with comprehensive fallback handling, loading states, and responsive sizing. Built on GPUI's native image support, it handles various image sources including URLs, local files, and SVG graphics with proper error handling and accessibility features.

Import

rust
use gpui::{img, ImageSource, ObjectFit};
use gpui_component::{v_flex, h_flex, div, Icon, IconName};

Usage

Basic Image

rust
// Simple image from URL
img("https://example.com/image.jpg")

// Local image file
img("assets/logo.png")

// SVG image
img("icons/star.svg")

Image with Sizing

rust
// Fixed dimensions
img("https://example.com/photo.jpg")
    .w(px(300.))
    .h(px(200.))

// Responsive width with aspect ratio
img("https://example.com/banner.jpg")
    .w(relative(1.))  // Full width
    .max_w(px(800.))
    .h(px(400.))

// Square image
img("https://example.com/avatar.jpg")
    .size(px(100.))  // 100x100px

Object Fit Options

Control how images are scaled and positioned within their containers:

rust
// Cover - scales to fill container, may crop
img("https://example.com/photo.jpg")
    .w(px(300.))
    .h(px(200.))
    .object_fit(ObjectFit::Cover)

// Contain - scales to fit within container, preserves aspect ratio
img("https://example.com/photo.jpg")
    .w(px(300.))
    .h(px(200.))
    .object_fit(ObjectFit::Contain)

// Fill - stretches to fill container, may distort
img("https://example.com/photo.jpg")
    .w(px(300.))
    .h(px(200.))
    .object_fit(ObjectFit::Fill)

// Scale Down - acts like contain, but never scales up
img("https://example.com/photo.jpg")
    .w(px(300.))
    .h(px(200.))
    .object_fit(ObjectFit::ScaleDown)

// None - original size, may overflow or be smaller than container
img("https://example.com/photo.jpg")
    .w(px(300.))
    .h(px(200.))
    .object_fit(ObjectFit::None)

Image with Fallback Handling

rust
// Basic fallback with placeholder
fn image_with_fallback(src: &str, alt_text: &str) -> impl IntoElement {
    div()
        .w(px(300.))
        .h(px(200.))
        .bg(cx.theme().surface)
        .border_1()
        .border_color(cx.theme().border)
        .rounded(px(8.))
        .overflow_hidden()
        .child(
            img(src)
                .w_full()
                .h_full()
                .object_fit(ObjectFit::Cover)
                // Add error handling in practice
        )
}

// Fallback with icon placeholder
fn image_with_icon_fallback(src: &str) -> impl IntoElement {
    div()
        .size(px(200.))
        .bg(cx.theme().surface)
        .border_1()
        .border_color(cx.theme().border)
        .rounded(px(8.))
        .flex()
        .items_center()
        .justify_center()
        .child(
            img(src)
                .size_full()
                .object_fit(ObjectFit::Cover)
                // On error, show icon:
                // Icon::new(IconName::Image)
                //     .size(px(48.))
                //     .text_color(cx.theme().muted_foreground)
        )
}

Loading States

rust
// Image with loading skeleton
fn image_with_loading(src: &str, is_loading: bool) -> impl IntoElement {
    div()
        .w(px(400.))
        .h(px(300.))
        .rounded(px(8.))
        .overflow_hidden()
        .map(|this| {
            if is_loading {
                this.bg(cx.theme().muted)
                    .flex()
                    .items_center()
                    .justify_center()
                    .child("Loading...")
            } else {
                this.child(
                    img(src)
                        .w_full()
                        .h_full()
                        .object_fit(ObjectFit::Cover)
                )
            }
        })
}

// Progressive loading with placeholder
fn progressive_image(src: &str, placeholder_src: &str) -> impl IntoElement {
    div()
        .relative()
        .w(px(400.))
        .h(px(300.))
        .rounded(px(8.))
        .overflow_hidden()
        .child(
            // Low-quality placeholder
            img(placeholder_src)
                .absolute()
                .inset_0()
                .w_full()
                .h_full()
                .object_fit(ObjectFit::Cover)
                .opacity(0.5)
        )
        .child(
            // High-quality image
            img(src)
                .absolute()
                .inset_0()
                .w_full()
                .h_full()
                .object_fit(ObjectFit::Cover)
        )
}

Responsive Images

rust
// Responsive grid images
fn responsive_image_grid() -> impl IntoElement {
    div()
        .grid()
        .grid_cols(3)
        .gap_4()
        .child(
            img("https://example.com/photo1.jpg")
                .w_full()
                .aspect_ratio(1.0)  // Square aspect ratio
                .object_fit(ObjectFit::Cover)
                .rounded(px(8.))
        )
        .child(
            img("https://example.com/photo2.jpg")
                .w_full()
                .aspect_ratio(1.0)
                .object_fit(ObjectFit::Cover)
                .rounded(px(8.))
        )
        .child(
            img("https://example.com/photo3.jpg")
                .w_full()
                .aspect_ratio(1.0)
                .object_fit(ObjectFit::Cover)
                .rounded(px(8.))
        )
}

// Hero image with text overlay
fn hero_image() -> impl IntoElement {
    div()
        .relative()
        .w_full()
        .h(px(500.))
        .rounded(px(12.))
        .overflow_hidden()
        .child(
            img("https://example.com/hero-image.jpg")
                .absolute()
                .inset_0()
                .w_full()
                .h_full()
                .object_fit(ObjectFit::Cover)
        )
        .child(
            div()
                .absolute()
                .inset_0()
                .bg(rgba(0, 0, 0, 0.4))  // Dark overlay
                .flex()
                .items_center()
                .justify_center()
                .child(
                    v_flex()
                        .items_center()
                        .gap_4()
                        .child("Hero Title")
                        .child("Subtitle text here")
                )
        )
}
rust
// Simple image gallery
fn image_gallery(images: Vec<&str>) -> impl IntoElement {
    v_flex()
        .gap_6()
        .child(
            // Main image
            div()
                .w_full()
                .h(px(400.))
                .rounded(px(12.))
                .overflow_hidden()
                .child(
                    img(images[0])
                        .w_full()
                        .h_full()
                        .object_fit(ObjectFit::Cover)
                )
        )
        .child(
            // Thumbnail row
            h_flex()
                .gap_3()
                .children(
                    images.iter().map(|src| {
                        div()
                            .size(px(80.))
                            .rounded(px(6.))
                            .overflow_hidden()
                            .border_2()
                            .border_color(cx.theme().border)
                            .cursor_pointer()
                            .hover(|this| this.border_color(cx.theme().primary))
                            .child(
                                img(*src)
                                    .size_full()
                                    .object_fit(ObjectFit::Cover)
                            )
                    })
                )
        )
}

SVG Images

rust
// SVG icon with custom styling
img("assets/icons/logo.svg")
    .size(px(64.))
    .text_color(cx.theme().primary)  // SVG color

// Inline SVG handling
img("data:image/svg+xml;base64,...")
    .w(px(32.))
    .h(px(32.))

// SVG with animation-friendly setup
img("assets/spinner.svg")
    .size(px(24.))
    .text_color(cx.theme().primary)
    // Add rotation animation in practice

API Reference

Core Image Function

FunctionDescription
img(source)Create image element from ImageSource

Image Sources (ImageSource)

TypeDescriptionExample
String/&strURL or file path"https://example.com/image.jpg"
SharedUriShared URI referenceSharedUri::from("file://path")
Local PathLocal file system path"assets/logo.png"
Data URIBase64 encoded image"data:image/png;base64,..."

Sizing Methods

MethodDescription
w(length)Set width
h(length)Set height
size(length)Set both width and height
w_full()Full width of container
h_full()Full height of container
size_full()Full size of container
max_w(length)Maximum width
max_h(length)Maximum height
min_w(length)Minimum width
min_h(length)Minimum height

Object Fit Options

ValueDescription
ObjectFit::CoverScale to fill container, may crop
ObjectFit::ContainScale to fit within container
ObjectFit::FillStretch to fill container
ObjectFit::ScaleDownLike contain, but never scale up
ObjectFit::NoneOriginal size

Styling Methods

MethodDescription
rounded(radius)Border radius
border_1()1px border
border_color(color)Border color
opacity(value)Image opacity (0.0-1.0)
shadow_sm()Small shadow
shadow_lg()Large shadow

Examples

Product Image Card

rust
use gpui_component::{v_flex, div, Icon, IconName};

fn product_card(image_src: &str, title: &str, price: &str) -> impl IntoElement {
    v_flex()
        .gap_3()
        .p_4()
        .bg(cx.theme().card)
        .rounded(px(12.))
        .shadow_sm()
        .child(
            div()
                .relative()
                .w_full()
                .h(px(200.))
                .rounded(px(8.))
                .overflow_hidden()
                .bg(cx.theme().muted)
                .child(
                    img(image_src)
                        .w_full()
                        .h_full()
                        .object_fit(ObjectFit::Cover)
                )
                .child(
                    // Wishlist button
                    div()
                        .absolute()
                        .top_2()
                        .right_2()
                        .size(px(32.))
                        .bg(rgba(255, 255, 255, 0.9))
                        .rounded_full()
                        .flex()
                        .items_center()
                        .justify_center()
                        .cursor_pointer()
                        .child(Icon::new(IconName::Heart).size(px(16.)))
                )
        )
        .child(title)
        .child(price)
}

Avatar with Image

rust
fn custom_avatar(src: &str, name: &str, size: f32) -> impl IntoElement {
    div()
        .size(px(size))
        .rounded_full()
        .overflow_hidden()
        .border_2()
        .border_color(cx.theme().background)
        .shadow_sm()
        .child(
            img(src)
                .size_full()
                .object_fit(ObjectFit::Cover)
        )
}

Image Comparison Slider

rust
fn image_comparison(before_src: &str, after_src: &str) -> impl IntoElement {
    div()
        .relative()
        .w_full()
        .h(px(400.))
        .rounded(px(12.))
        .overflow_hidden()
        .child(
            // Before image
            img(before_src)
                .absolute()
                .inset_0()
                .w_full()
                .h_full()
                .object_fit(ObjectFit::Cover)
        )
        .child(
            // After image with clip
            div()
                .absolute()
                .top_0()
                .left_0()
                .w(relative(0.5))  // Show 50% initially
                .h_full()
                .overflow_hidden()
                .child(
                    img(after_src)
                        .w(px(800.))  // Full width of container
                        .h_full()
                        .object_fit(ObjectFit::Cover)
                )
        )
        .child(
            // Divider line
            div()
                .absolute()
                .top_0()
                .left(relative(0.5))
                .w(px(2.))
                .h_full()
                .bg(cx.theme().primary)
        )
}

Error Handling Pattern

rust
enum ImageState {
    Loading,
    Loaded,
    Error,
}

fn robust_image(src: &str, state: ImageState) -> impl IntoElement {
    div()
        .w(px(300.))
        .h(px(200.))
        .bg(cx.theme().muted)
        .rounded(px(8.))
        .border_1()
        .border_color(cx.theme().border)
        .flex()
        .items_center()
        .justify_center()
        .map(|this| {
            match state {
                ImageState::Loading => {
                    this.child(
                        v_flex()
                            .items_center()
                            .gap_2()
                            .child(Icon::new(IconName::Loader2).size(px(24.)))
                            .child("Loading...")
                    )
                }
                ImageState::Loaded => {
                    this.p_0()
                        .overflow_hidden()
                        .child(
                            img(src)
                                .w_full()
                                .h_full()
                                .object_fit(ObjectFit::Cover)
                        )
                }
                ImageState::Error => {
                    this.child(
                        v_flex()
                            .items_center()
                            .gap_2()
                            .child(
                                Icon::new(IconName::ImageOff)
                                    .size(px(32.))
                                    .text_color(cx.theme().muted_foreground)
                            )
                            .child("Failed to load image")
                    )
                }
            }
        })
}

Accessibility

Alt Text and Labels

  • Use semantic HTML structure for screen readers
  • Provide descriptive image context through surrounding elements
  • Include image descriptions in component documentation

Keyboard Navigation

  • Images within interactive containers support proper focus management
  • Implement keyboard shortcuts for image galleries and carousels
  • Ensure interactive image elements are reachable via tab navigation

Loading States

  • Provide loading indicators for slow-loading images
  • Use skeleton screens to maintain layout stability
  • Announce loading state changes to screen readers

Color and Contrast

  • Ensure sufficient contrast for text overlays on images
  • Provide alternative text descriptions for informational images
  • Consider color-blind accessibility when using color-coded image states

Performance Considerations

  • Use appropriate image formats (WebP, AVIF when supported)
  • Implement lazy loading for images below the fold
  • Provide multiple image sizes for responsive displays
  • Use proper caching strategies for frequently accessed images

Best Practices

Image Optimization

  • Use appropriate image dimensions for display size
  • Compress images without sacrificing quality
  • Consider using modern image formats (WebP, AVIF)
  • Implement responsive images for different screen sizes

Error Handling

  • Always provide meaningful fallbacks for failed image loads
  • Use skeleton loading states to maintain layout stability
  • Implement retry mechanisms for temporary network failures
  • Provide user feedback for permanent load failures

Performance

  • Use lazy loading for images not immediately visible
  • Implement proper caching strategies
  • Consider using placeholder images during loading
  • Optimize image sizes for their display context

User Experience

  • Maintain consistent aspect ratios in image grids
  • Provide smooth loading transitions
  • Use appropriate object-fit values for content type
  • Consider providing zoom functionality for detailed images

Implementation Notes

GPUI Integration

  • Built on GPUI's native image rendering capabilities
  • Supports all GPUI ImageSource types automatically
  • Inherits GPUI's styling and layout system
  • Compatible with GPUI's animation and interaction systems

SVG Support

  • Full support for SVG graphics with proper scaling
  • SVG images can be styled with text colors for theming
  • Vector graphics maintain sharpness at all sizes
  • Supports both external SVG files and inline data URIs

Memory Management

  • GPUI handles image caching and memory management automatically
  • Large images are efficiently managed by the graphics backend
  • No manual memory cleanup required for image components

Cross-Platform Compatibility

  • Consistent behavior across Windows, macOS, and Linux
  • Native image format support varies by platform
  • Uses platform-optimized rendering where available