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")
)
)
}
Image Gallery
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
Function | Description |
---|---|
img(source) | Create image element from ImageSource |
Image Sources (ImageSource)
Type | Description | Example |
---|---|---|
String/&str | URL or file path | "https://example.com/image.jpg" |
SharedUri | Shared URI reference | SharedUri::from("file://path") |
Local Path | Local file system path | "assets/logo.png" |
Data URI | Base64 encoded image | "data:image/png;base64,..." |
Sizing Methods
Method | Description |
---|---|
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
Value | Description |
---|---|
ObjectFit::Cover | Scale to fill container, may crop |
ObjectFit::Contain | Scale to fit within container |
ObjectFit::Fill | Stretch to fill container |
ObjectFit::ScaleDown | Like contain, but never scale up |
ObjectFit::None | Original size |
Styling Methods
Method | Description |
---|---|
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