Blur image
FreeAn image that sharpens into place over a blurred placeholder at its final size, and shows its description if it fails.
pnpm dlx shadcn@latest add https://caliperui.site/r/blur-image.jsonWhen 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.