Documentation

Image and Icon Components

Display images from URLs, resources, or bitmaps, plus Material Design icons.

Image Component

From URL

<Image src="https://example.com/photo.jpg" />

From Bitmap

val bitmap = loadBitmap()
<Image bitmap={bitmap} />

Size Control

<Image src={url} w={200} h={200} />
<Image src={url} fillMaxWidth h={300} />

Aspect Ratio

Maintain aspect ratio while fitting container:

<Image src={url} aspectRatio={16.0/9.0} />
<Image src={url} aspectRatio={1.0} />  <!-- Square -->

Content Scale

Control how images fit within their bounds:

<Image src={url} fit="crop" />    <!-- Fill, cropping if needed -->
<Image src={url} fit="fit" />     <!-- Fit inside, may have empty space -->
<Image src={url} fit="fillWidth" />
<Image src={url} fit="fillHeight" />
Fit ValueEffect
"crop"Fill bounds, crop overflow
"fit"Fit inside bounds, maintain aspect ratio
"fillWidth"Fill width, scale height proportionally
"fillHeight"Fill height, scale width proportionally
"fillBounds"Fill both dimensions (may distort)

Corner Radius

<Image src={url} cornerRadius={8} />
<Image src={url} cornerRadius={100} />  <!-- Circle -->

Circular Images

<Image src={avatar} w={48} h={48} cornerRadius={24} />

Overlay Gradient

Add gradient overlays for better text contrast:

<Image
  src={poster}
  overlay="v-gradient(transparent 60%, #000)"
  h={400}
/>
<Box>
  <Image src={photo} />
  <Box
    background="v-gradient(transparent 60%, #000)"
    fillMaxSize
  />
  <Text color="#FFF" p={16}>Caption</Text>
</Box>

Loading State

<Image
  src={url}
  placeholder={R.drawable.placeholder}
  error={R.drawable.error}
/>

Clickable Images

Images support onClick like any component:

<Image
  src={product.image}
  onClick={() => $navigate("/product/{product.id}")}
/>

Icon Component

Basic Usage

<Icon name="home" />
<Icon name="favorite" />
<Icon name="settings" />

Size

<Icon name="star" size={16} />
<Icon name="star" size={24} />
<Icon name="star" size={48} />

Color

<Icon name="favorite" color="primary" />
<Icon name="error" color="error" />
<Icon name="check" color="#00FF00" />

Rotation

<Icon name="arrow-forward" rotate={90} />   <!-- Down -->
<Icon name="arrow-forward" rotate={180} />  <!-- Back -->
<Icon name="arrow-forward" rotate={270} />  <!-- Up -->

Icon Sets

Access different icon sets with prefixes:

<Icon name="home" />                    <!-- Material Default -->
<Icon name="solar:star-bold" />         <!-- Solar Icons -->
<Icon name="lucide:heart" />            <!-- Lucide Icons -->

Naming Convention

Icons use kebab-case and automatically map to PascalCase:

  • arrow-forwardIcons.Default.ArrowForward
  • solar:star-boldIcons.Solar.StarBold

Common Patterns

Avatar

<Image
  src={user.avatar}
  w={40} h={40}
  cornerRadius={20}
/>

Hero Image

<Box>
  <Image
    src={article.cover}
    fillMaxWidth
    h={250}
    fit="crop"
  />
  <Box
    background="v-gradient(transparent 50%, #000)"
    fillMaxSize
  />
  <Column
    fillMaxSize
    verticalArrangement="end"
    p={20}
  >
    <Text fontSize={28} fontWeight="bold" color="#FFF">
      {article.title}
    </Text>
  </Column>
</Box>

Product Card

<Card onClick={() => $navigate("/product/{product.id}")}>
  <Image
    src={product.image}
    fillMaxWidth
    aspectRatio={1.0}
    fit="crop"
  />
  <Column p={12} gap={4}>
    <Text fontSize={14} maxLines={2}>{product.name}</Text>
    <Row gap={4} verticalAlignment="center">
      <Icon name="star" size={16} color="primary" />
      <Text fontSize={12}>{product.rating}</Text>
    </Row>
    <Text fontSize={16} fontWeight="bold">${product.price}</Text>
  </Column>
</Card>

Icon with Label

<Column horizontalAlignment="center" gap={4}>
  <Icon name="shopping-cart" size={32} color="primary" />
  <Text fontSize={12}>Cart</Text>
</Column>

Icon Button

<Button onClick={toggleFavorite}>
  <Icon
    name={isFavorite ? "favorite" : "favorite-border"}
    color={isFavorite ? "error" : "secondary"}
  />
</Button>

Rating Stars

val rating = 4.5

<Row gap={4}>
  @for (i in 1..5) {
    <Icon
      name={if (i <= rating) "star" else "star-border"}
      color="primary"
      size={20}
    />
  }
  <Text fontSize={14} color="secondary">({reviewCount})</Text>
</Row>

Image Gallery Grid

<LazyVerticalGrid columns={3} gap={2}>
  @for (photo in photos) {
    <Image
      src={photo.thumbnail}
      aspectRatio={1.0}
      fit="crop"
      onClick={() => $navigate("/photo/{photo.id}")}
      transition:crossfade="photo-{photo.id}"
    />
  }
</LazyVerticalGrid>

Background Image

<Box fillMaxSize>
  <Image
    src={backgroundUrl}
    fillMaxSize
    fit="crop"
  />
  <Box
    background="v-gradient(transparent, #000000CC)"
    fillMaxSize
  />
  <Column fillMaxSize p={20} verticalArrangement="center">
    <Text fontSize={32} color="#FFF" fontWeight="bold">
      Welcome
    </Text>
  </Column>
</Box>

Profile Header

<Column>
  <Box h={200}>
    <Image src={user.coverPhoto} fillMaxSize fit="crop" />
  </Box>
  <Row p={16} gap={16}>
    <Image
      src={user.avatar}
      w={80} h={80}
      cornerRadius={40}
      mt={-40}  <!-- Overlap cover photo -->
    />
    <Column weight={1}>
      <Text fontSize={24} fontWeight="bold">{user.name}</Text>
      <Text fontSize={14} color="secondary">{user.bio}</Text>
    </Column>
  </Row>
</Column>

Prop Reference

Image Props

PropTypeDescription
srcStringImage URL
bitmapBitmapBitmap object
fitStringContent scale mode
aspectRatioNumberWidth/height ratio
cornerRadiusNumberCorner radius in dp
overlayStringGradient overlay
placeholderResourceLoading placeholder
errorResourceError fallback

Icon Props

PropTypeDescription
nameStringIcon name (kebab-case)
sizeNumberIcon size in dp
colorStringIcon color
tintStringAlias for color
rotateNumberRotation in degrees

See Also