@mshafiqyajid/react-image
Headless hook + styled wrapper for images. Native lazy loading, skeleton shimmer, blur-up placeholder, graceful error fallback with custom content, aspect ratio, object-fit, and radius variants.
Playground #
Props
TSX
import { ImageStyled } from "@mshafiqyajid/react-image/styled";
import "@mshafiqyajid/react-image/styles.css";
<ImageStyled />Install #
npm install @mshafiqyajid/react-image Quick start #
import { ImageStyled } from "@mshafiqyajid/react-image/styled";
import "@mshafiqyajid/react-image/styles.css";
<ImageStyled
src="https://picsum.photos/800/600"
alt="A scenic photo"
aspectRatio="4/3"
radius="md"
placeholder="skeleton"
/> Blur-up placeholder #
Pass a tiny base64 data URL as blurDataURL. It renders blurred behind the main image until the full image loads.
<ImageStyled
src="https://picsum.photos/800/600"
alt="Landscape"
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AA..."
aspectRatio="16/9"
/> Fallback on error #
// Auto-retry with fallback URL
<ImageStyled
src="/uploads/photo.jpg"
alt="User photo"
fallbackSrc="/images/placeholder.jpg"
/>
// Custom error content
<ImageStyled
src="/uploads/photo.jpg"
alt="User photo"
fallback={<div className="error-state">Image unavailable</div>}
/> Headless #
import { useImage } from "@mshafiqyajid/react-image";
const { imgProps, isLoading, isLoaded, isError } = useImage({
src: "https://example.com/photo.jpg",
alt: "A photo",
fallbackSrc: "https://example.com/fallback.jpg",
lazy: true,
onLoad: () => console.log("loaded"),
onError: () => console.error("failed"),
});
return (
<div style={{ position: "relative", width: 400, height: 300 }}>
{isLoading && <div className="my-skeleton" />}
{!isError && <img {...imgProps} style={{ width: "100%", height: "100%", objectFit: "cover" }} />}
{isError && <div>Could not load image</div>}
</div>
); Decorative images #
Pass an empty alt="" for purely decorative images. The hook automatically adds aria-hidden="true".
<ImageStyled src="/decorative-bg.jpg" alt="" /> API #
| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | — | Image source URL |
| alt | string | — | Alt text. Empty string marks image as decorative (aria-hidden) |
| fallbackSrc | string | — | URL to try if src fails to load |
| fallback | ReactNode | — | Custom content shown in error state |
| placeholder | "blur" | "skeleton" | "color" | "none" | "skeleton" | Loading placeholder strategy |
| blurDataURL | string | — | Tiny base64 image for blur placeholder |
| placeholderColor | string | — | Background color for "color" placeholder |
| lazy | boolean | true | Use native lazy loading attribute |
| aspectRatio | string | number | — | CSS aspect-ratio (e.g. "4/3", "16/9") |
| objectFit | "cover" | "contain" | "fill" | "none" | "scale-down" | "cover" | CSS object-fit |
| objectPosition | string | "center" | CSS object-position |
| width | number | string | — | Explicit width on the wrapper element |
| height | number | string | — | Explicit height on the wrapper element |
| crossOrigin | "anonymous" | "use-credentials" | — | Sets the crossorigin attribute on the img element |
| radius | "none" | "xs" | "sm" | "md" | "lg" | "full" | "none" | Border radius |
| onLoad | () => void | — | Callback when image successfully loads |
| onError | () => void | — | Callback when all load attempts fail |
| className | string | — | Extra class on the root wrapper element |
| style | CSSProperties | — | Inline style override |