caliper uidocs

Blur image

Free

An image that sharpens into place over a blurred placeholder at its final size, and shows its description if it fails.

Installs components/ui/blur-image.tsxDepends on lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/blur-image.json

When to use #

Use it for

  • Galleries, product images and avatars from slow sources.
  • Feeds where layout must not jump.

Skip it when

  • Icons and small UI images; they load instantly.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/blur-image.json

Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { useEffect, useRef, useState } from "react"
import { BlurImage } from "@/components/ui/blur-image"
import { Button } from "@/components/ui/button"

export function BlurImageDemo() {
  const [round, setRound] = useState(0);
  const [src, setSrc] = useState<string | null>(null);
  const timer = useRef<ReturnType<typeof setTimeout>>(undefined);
  useEffect(() => {
    // The sample image is local and instant, so the demo waits a moment to show the placeholder.
    timer.current = setTimeout(() => setSrc(`/media/harbour.svg?v=${round}`), 900);
    return () => clearTimeout(timer.current);
  }, [round]);
  return (
    <div className="grid w-full max-w-sm gap-3">
      <div className="overflow-hidden rounded-[14px]">
        {src ? <BlurImage key={src} src={src} alt="Harbour at dusk" width={640} height={400} placeholder="#9bb3c7" /> : <span className="block aspect-[640/400] bg-[#9bb3c7] blur-sm" aria-hidden="true" />}
      </div>
      <Button size="sm" variant="secondary" className="w-fit" onClick={() => { setSrc(null); setRound((n) => n + 1); }}>Load again</Button>
    </div>
  );
}

API reference #

BlurImage

component

Also accepts the native props of its root element and a ref.

PropTypeDefaultDescription
width *number—Intrinsic size, so the space is held before it loads.
height *number—
placeholderstring—A tiny data URL or a CSS colour shown blurred until the image arrives.
imgClassNamestring—

Accessibility #

It exposes img semantics, with aria-label and aria-hidden kept in step with state.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.