npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@pagedotapp/page-image

v0.0.0-alpha.14

Published

PageImage - A reusable React component

Readme

PageImage

A flexible image component with loading states, fallback support, and various display options.

Installation

npm install @pagedotapp/page-image

Usage

import { PageImage } from "@pagedotapp/page-image"

function App() {
	return (
		<PageImage
			src="/path/to/image.jpg"
			alt="Description of image"
			width={400}
			height={300}
			fallback={<div>Failed to load</div>}
		/>
	)
}

Props

| Prop | Type | Default | Description | | -------------------- | ------------------------------ | ------------ | ------------------------------------------------------------ | | src | string | - | Image source URL (required) | | alt | string | - | Alternative text for accessibility (required) | | fallback | React.ReactNode | Default icon | Fallback content when image fails to load | | fallbackSrc | string | - | Fallback image URL to try if main src fails | | width | string \| number | - | Width of the image container | | height | string \| number | - | Height of the image container | | fit | ImageFit | 'cover' | Object fit behavior (contain, cover, fill, none, scale-down) | | aspectRatio | ImageAspectRatio | 'auto' | Aspect ratio (auto, square, 4/3, 16/9, 21/9, 9/16, 3/4) | | loading | 'eager' \| 'lazy' | 'lazy' | Loading strategy | | showSkeleton | boolean | true | Whether to show loading skeleton | | rounded | boolean | false | Whether the image should be rounded | | circle | boolean | false | Whether the image should be circular | | radius | 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Border radius size (when rounded) | | className | string | '' | Additional CSS class name for the image | | containerClassName | string | '' | Additional CSS class name for the container | | onLoad | function | - | Called when image loads successfully | | onError | function | - | Called when image fails to load | | fadeIn | boolean | true | Whether to fade in on load | | onClick | function | - | Click handler for the image |

Examples

Basic Usage

<PageImage src="https://example.com/photo.jpg" alt="Example photo" />

With Dimensions and Aspect Ratio

// Fixed dimensions
<PageImage
  src="/hero-image.jpg"
  alt="Hero image"
  width={800}
  height={400}
/>

// Aspect ratio
<PageImage
  src="/photo.jpg"
  alt="Photo"
  aspectRatio="16/9"
  width="100%"
/>

// Square image
<PageImage
  src="/avatar.jpg"
  alt="User avatar"
  aspectRatio="square"
  width={200}
/>

Object Fit Options

<PageImage
  src="/banner.jpg"
  alt="Banner"
  fit="cover"  // Default - covers entire container
  aspectRatio="21/9"
/>

<PageImage
  src="/logo.png"
  alt="Logo"
  fit="contain"  // Maintains aspect ratio within container
  width={200}
  height={100}
/>

Shape Variants

// Circular image (perfect for avatars)
<PageImage
  src="/avatar.jpg"
  alt="User avatar"
  circle
  width={100}
  height={100}
/>

// Rounded corners
<PageImage
  src="/card-image.jpg"
  alt="Card image"
  rounded
  radius="lg"
/>

Loading States

// With skeleton loader (default)
<PageImage
  src="/slow-loading.jpg"
  alt="Slow loading image"
  showSkeleton
/>

// Without skeleton loader
<PageImage
  src="/fast-loading.jpg"
  alt="Fast loading image"
  showSkeleton={false}
/>

// Eager loading for above-the-fold images
<PageImage
  src="/hero.jpg"
  alt="Hero image"
  loading="eager"
/>

Error Handling

// With custom fallback content
<PageImage
  src="/might-fail.jpg"
  alt="Image that might fail"
  fallback={
    <div style={{ padding: '2rem', textAlign: 'center' }}>
      <p>Unable to load image</p>
      <button>Retry</button>
    </div>
  }
/>

// With fallback image
<PageImage
  src="/primary-image.jpg"
  alt="Product photo"
  fallbackSrc="/placeholder.jpg"
/>

// Handle load/error events
<PageImage
  src="/tracked-image.jpg"
  alt="Tracked image"
  onLoad={() => console.log('Image loaded successfully')}
  onError={() => console.log('Image failed to load')}
/>

Interactive Images

// Clickable image with proper accessibility
<PageImage
  src="/clickable.jpg"
  alt="Click to enlarge"
  onClick={(e) => console.log('Image clicked')}
  style={{ cursor: 'pointer' }}
/>

// Image gallery item
<PageImage
  src="/gallery-item.jpg"
  alt="Gallery item"
  onClick={() => openLightbox()}
  rounded
  fadeIn
/>

Advanced Examples

// Product image with all features
<PageImage
  src={product.imageUrl}
  alt={product.name}
  fallbackSrc="/product-placeholder.jpg"
  aspectRatio="4/3"
  fit="contain"
  rounded
  radius="md"
  fadeIn
  loading="lazy"
  onClick={() => setShowZoom(true)}
  className="product-image"
  containerClassName="product-image-container"
/>

// Avatar with fallback
<PageImage
  src={user.avatarUrl}
  alt={`${user.name}'s avatar`}
  fallback={
    <div className="avatar-fallback">
      {user.name.charAt(0)}
    </div>
  }
  circle
  width={60}
  height={60}
/>

// Hero banner with specific handling
<PageImage
  src="/hero-banner.jpg"
  alt="Welcome to our site"
  aspectRatio="21/9"
  fit="cover"
  loading="eager"
  showSkeleton
  fadeIn={false}  // No fade for hero images
  onLoad={() => setHeroLoaded(true)}
/>

Default Fallback

When an image fails to load and no custom fallback is provided, the component displays a default fallback with:

  • A subtle image icon
  • The alt text as a caption
  • Proper styling to match your design

TypeScript

The component exports the following types:

import type {
	PageImageProps,
	ImageFit,
	ImageAspectRatio,
	ImageLoadingStrategy,
} from "@pagedotapp/page-image"

Styling

The component uses CSS modules for styling. You can override styles by:

  • Passing a custom className for the image element
  • Passing a custom containerClassName for the container
  • Targeting the component's CSS classes in your global styles

Accessibility

  • Always provide meaningful alt text
  • When using onClick, the component automatically adds role="button" and tabIndex={0}
  • The component maintains proper aspect ratios to prevent layout shift

Performance

  • Lazy loading is enabled by default
  • Images fade in smoothly when loaded (can be disabled)
  • Skeleton loader provides visual feedback during loading
  • Prevents layout shift with proper aspect ratio handling

Development

To run the component in development mode:

npm run storybook

To run tests:

npm run test

To lint the component:

npm run lint