<smart-image>

SmartImage

A declarative, attribute-driven image Web Component with lazy loading, shimmer and spinner skeletons, fade-in animation, fallback on error, rounded/circle shapes, hover zoom, click-to-preview modal, aspect ratio, and captions — all from HTML attributes.

Lazy Load Shimmer Skeleton Fallback Hover Zoom Click Preview Aspect Ratio
<script src="smart-image.js"></script>

Live Playground

Toggle attributes on the left to see the real <smart-image> component update live.

Controls

<smart-image
  src="https://picsum.photos/id/10/560/360"
  width="280"
  height="180"
  caption="Mountain lake at dusk"
  animation-type="shimmer"
  fit="cover"
  rounded
></smart-image>

Lazy Loading

Images are lazy-loaded by default via IntersectionObserver — the network request only fires when the image enters the viewport. Set lazy="false" to force an eager load.

<!-- Default: lazy load via IntersectionObserver -->
<smart-image
  src="/media/photo.jpg"
  width="300"
  height="200"
></smart-image>

<!-- Eager: loads immediately regardless of viewport -->
<smart-image
  src="/media/hero.jpg"
  lazy="false"
  width="1200"
  height="600"
></smart-image>

Skeleton Types

While the image loads, a placeholder skeleton is shown. shimmer (default when width & height are set) animates a gradient sweep. spinner shows a rotating ring — useful for circular avatars or when dimensions aren't fixed.

<smart-image
  src="/media/photo.jpg"
  width="300"
  height="200"
  animation-type="shimmer"
></smart-image>

<smart-image
  src="/media/avatar.jpg"
  width="80"
  height="80"
  animation-type="spinner"
  circle
></smart-image>

Rounded & Circle

Use rounded for a card-style corner radius, or circle for a perfect circular crop — ideal for avatars.

<smart-image src="..." width="220" height="160"></smart-image>

<smart-image src="..." width="220" height="160" rounded></smart-image>

<smart-image src="..." width="80" height="80" circle></smart-image>

Hover Zoom

Add hover-zoom to scale the image to 107% on hover with a smooth cubic-bezier transition. The image is clipped by its wrapper so no layout shift occurs.

<smart-image
  src="/media/photo.jpg"
  width="300"
  height="200"
  rounded
  hover-zoom
></smart-image>

Click Preview

Add click-preview to open a fullscreen lightbox modal when the image is clicked. Press Esc or click outside to close.

<smart-image
  src="/media/photo.jpg"
  width="300"
  height="200"
  rounded
  hover-zoom
  click-preview
  caption="Click to open preview"
></smart-image>

Aspect Ratio

Use aspect-ratio instead of a fixed height for fluid, responsive images. Combine with fit to control how the image fills the box (cover, contain, fill).

<!-- Fluid 16:9 banner — scales with its container -->
<smart-image
  src="/media/banner.jpg"
  aspect-ratio="16/9"
  style="width:100%"
  fit="cover"
  rounded
></smart-image>

<!-- Square thumbnail -->
<smart-image
  src="/media/thumb.jpg"
  aspect-ratio="1/1"
  style="width:120px"
  fit="cover"
  rounded
></smart-image>

Fallback & Error

Set fallback-src to automatically try a second image if the primary URL fails. If the fallback also fails, a broken-image placeholder with a Retry button is shown. An image-error event fires either way.

<!-- With fallback — tries a second URL on error -->
<smart-image
  src="/media/user-upload.jpg"
  fallback-src="/media/placeholder.jpg"
  width="200"
  height="200"
  rounded
></smart-image>

<!-- Without fallback — shows retry UI on error -->
<smart-image
  src="/media/might-fail.jpg"
  width="200"
  height="200"
  rounded
></smart-image>

Caption

Add a caption attribute to render a small text label beneath the image wrapper. Use alt for screen reader accessibility — it is separate from the visible caption.

<smart-image
  src="/media/meadow.jpg"
  width="300"
  height="200"
  rounded
  caption="Alpine meadow, July 2024"
  alt="Photo of an alpine meadow"
></smart-image>

Attributes

AttributeTypeDescriptionDefault
src string Required. The image URL to load.
fallback-src string A secondary URL to attempt if src fails. Only tried once.
alt string Alternative text for the <img> element — used by screen readers. ""
caption string Visible text rendered below the image wrapper as a small <p>.
width number | string Sets the wrapper width. Numbers are converted to px; strings are used as-is (e.g. "100%").
height number | string Sets the wrapper height. Same rules as width.
aspect-ratio string CSS aspect-ratio value (e.g. "16/9", "1/1"). Use instead of a fixed height for fluid images.
fit string CSS object-fit value for the image inside its wrapper. Options: cover, contain, fill. cover
animation-type string Skeleton style while loading. shimmer shows a gradient sweep; spinner shows a rotating ring. Auto-selected based on whether width & height are set. shimmer
rounded boolean Adds a 10px border-radius to the wrapper for a card-style appearance. false
circle boolean Clips the image into a perfect circle. Best used with equal width and height. false
hover-zoom boolean Scales the image to 107% on hover with a smooth transition. Clipped to the wrapper bounds. false
click-preview boolean Opens a fullscreen lightbox modal on click. Close with Esc or click outside. false
lazy boolean Set to "false" to load the image immediately regardless of viewport position. true

Events

EventdetailFires when
image-loaded { src } The image has loaded and the fade-in animation has started.
image-error { src } Both the primary src and fallback-src (if set) have failed to load.
const img = document.querySelector('smart-image');

img.addEventListener('image-loaded', (e) => {
  console.log('Image loaded:', e.detail.src);
});

img.addEventListener('image-error', (e) => {
  console.warn('Image failed:', e.detail.src);
  // log to error tracking, swap in a different URL, etc.
});