Skip to content

VImage

The main component. Combines lazy loading, placeholder, format switching, and transitions in one element.

vue
<VImage
  src="/photo.jpg"
  alt="Описание"
  :width="1200"
  :height="600"
  blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
  placeholder="data:image/jpeg;base64,..."
  :widths="[400, 800, 1200]"
  sizes="(max-width: 768px) 100vw, 50vw"
  :lazy="true"
  root-margin="300px"
  fit="cover"
  @load="onLoad"
  @error="onError"
>
  <template #error>
    <div class="my-error">Image failed to load</div>
  </template>
</VImage>

Props

PropTypeDefaultDescription
srcstring | SrcSetURL or object with format variants. Optional when image is given
imageImageMetaBuild-time metadata (a CLI manifest entry or ?vik import) — seeds src/width/height/blurhash/thumbhash/placeholder/sizes. Any explicit prop above overrides the matching field
altstringRequired. alt attribute on the <img>. In dev builds, a suspicious value (missing, whitespace-only, or filename-shaped like "photo.jpg") logs a console.warn — a deliberate alt="" for a decorative image never triggers it
widthnumberIntrinsic width; used to reserve aspect-ratio space
heightnumberIntrinsic height; used to reserve aspect-ratio space
blurhashstringBlurHash string; decoded to canvas in onMounted
thumbhashstringThumbHash string; decoded to PNG data URL, used as blur-up placeholder
placeholderstringBase64 LQIP or ThumbHash data URL; overrides thumbhash if both provided
placeholderMode'blur' | 'color' | 'shimmer''blur''color' shows a solid average color (from thumbhash); 'shimmer' shows an animated skeleton (no hash needed)
placeholderColorstringExplicit solid CSS color placeholder; takes precedence and needs no decode
widthsnumber[]Pixel widths for automatic width-based (w) srcset generation
densitiesnumber[] | Record<number, string>Density descriptors (1x/2x/3x) for fixed-size images. List reuses src; map gives a distinct file per density. Takes precedence over widths, ignores sizes
sizesstringsizes attribute passed to <img> (width-based srcset only)
breakpointsBreakpointMapLocal breakpoints (merged with global plugin breakpoints)
sourcesResponsiveSrcBreakpoint-key → URL (or { avif?, webp?, fallback }) map for art direction, optionally combined with format switching per breakpoint
lazybooleantrueEnable IntersectionObserver lazy loading
rootMarginstring"200px"IO rootMargin — how far before the viewport loading starts
thresholdnumber0IO threshold — intersection ratio required to trigger
fitObjectFit"cover"CSS object-fit value on the <img>
focalFocalPointFocal point { x, y } (fractions 0–1) → object-position; keeps the subject in frame when fit="cover" crops
maxRetriesnumber0Max retry attempts on load failure
retryDelaynumber1000Initial delay in ms; doubles each retry (exponential backoff)
fetchpriority'high' | 'low' | 'auto'Browser fetch priority hint
decoding'async' | 'sync' | 'auto''async'Image decoding mode
prioritybooleanfalseShorthand for the LCP/hero image — forces lazy=false, fetchpriority='high', decoding='sync'. Not automatic LCP detection (that isn't reliable pre-paint); mark the one image that matters instead of setting three props by hand
respectSaveDatabooleanfalseOn a save-data connection: neutralizes priority (stays lazy) and downgrades src to the smallest URL available from densities/image.srcset. See Network-aware loading
layout'fixed' | 'responsive' | 'fill'Wrapper sizing preset. Unset keeps the current default (fills container width, aspect-ratio preserved). See Layout presets
cdnboolean | AutoLoaderConfigOpt-in: routes a string src through autoLoader() — detects the CDN from the URL and rewrites it, no manual adapter wiring. See CDN adapters → Auto CDN detection with VImage
loader'server'Opt-in: routes a string src through the vue-image-kit/server on-demand handler via buildImageUrl(). See Self-hosted on-demand server → Wiring VImage to it
loaderRoutestring/_vik/imageRoute override for loader="server" — takes precedence over the plugin/Nuxt-module serverRoute default

Events

EventPayloadDescription
@loadEventFired when the image finishes loading
@errorEventFired when the image fails to load

Slots

SlotDescription
#errorCustom UI shown when the image fails to load. If omitted, a grey rectangle with a broken-image icon is shown.

Examples

Simple image with lazy loading:

vue
<VImage src="/photo.jpg" alt="Landscape" />

With blurhash and dimensions for aspect-ratio reservation:

vue
<VImage
  src="/photo.jpg"
  alt="Landscape"
  :width="1200"
  :height="800"
  blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
/>

WebP/AVIF with srcset and blur-up:

vue
<VImage
  :src="{ avif: '/photo.avif', webp: '/photo.webp', fallback: '/photo.jpg' }"
  alt="Product"
  :width="800"
  :height="600"
  placeholder="data:image/jpeg;base64,/9j/4AAQSkZJRgAB..."
  :widths="[400, 800]"
  sizes="(max-width: 640px) 100vw, 800px"
/>

Disable lazy loading for above-the-fold images:

vue
<VImage src="/hero.jpg" alt="Hero" :lazy="false" />

LCP/hero image — priority instead of three separate props:

vue
<VImage src="/hero.jpg" alt="Hero" :width="1600" :height="900" priority />

From CLI/manifest output — no manual prop wiring:

vue
<script setup lang="ts">
import meta from './photo.jpg?vik' // or: import { images } from './assets/images'
</script>

<template>
  <!-- src/width/height/blurhash/thumbhash/placeholder/sizes all come from meta -->
  <VImage :image="meta" alt="Product photo" />
</template>

Focal point — keep the subject in frame when cropping:

vue
<!-- With fit="cover" the image is cropped to the box; focal decides which
     part survives. { x: 0.5, y: 0.3 } favours the upper-middle (e.g. a face). -->
<VImage
  src="/portrait.jpg"
  alt="Team member"
  :width="400"
  :height="400"
  fit="cover"
  :focal="{ x: 0.5, y: 0.3 }"
/>

Cheapest placeholder — a solid average color (no canvas, 0 bytes):

vue
<!-- 'color' mode pulls the average RGBA straight from the ThumbHash header. -->
<VImage
  src="/photo.jpg"
  alt="Gallery item"
  :width="600"
  :height="400"
  thumbhash="3OcRJYB4d3h/iIeHeEh3eIhw+j5n"
  placeholder-mode="color"
/>

<!-- Or an explicit color you already know — needs no ThumbHash at all. -->
<VImage src="/photo.jpg" alt="Banner" placeholder-color="#1e3a8a" />

Animated skeleton — when you have no hash at all:

vue
<!-- A CSS shimmer sweep until the image loads. Respects prefers-reduced-motion. -->
<VImage src="/photo.jpg" alt="Card" :width="400" :height="300" placeholder-mode="shimmer" />

Custom error slot:

vue
<VImage src="/missing.jpg" alt="Missing">
  <template #error>
    <div class="placeholder">
      <span>📷</span>
      <p>Image unavailable</p>
    </div>
  </template>
</VImage>

Handling events:

vue
<script setup lang="ts">
function onLoad(e: Event) {
  console.log('Image loaded', e)
}
function onError(e: Event) {
  console.warn('Image failed', e)
}
</script>

<template>
  <VImage src="/photo.jpg" alt="Photo" @load="onLoad" @error="onError" />
</template>