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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-shrink

v1.0.0

Published

Blazing-fast client-side image compression library for React with Web Worker support. Compress images 70-99% with WebP, AVIF, JPEG. Zero dependencies, TypeScript-first.

Readme

React-Shrink

Blazing-fast client-side image compression library for React with Web Worker support

npm version npm downloads Bundle Size TypeScript License

Compress images in the browser | Reduce file sizes by 70-99% | WebP, AVIF, JPEG support | Zero dependencies

Intelligent image compression engine for React applications. Optimize images client-side before upload with adaptive quality algorithms, Web Worker parallelization, and automatic format selection. Perfect for React, Next.js, and Vite projects.

Quick Start · API Docs · Live Examples · Benchmarks


✨ Key Features

Image Compression & Optimization:

  • 🚀 Web Worker Compression - Non-blocking, parallel image processing
  • 🎯 Adaptive Quality - Binary search algorithm meets exact size targets (300KB, 500KB, 1MB)
  • 🖼️ Modern Image Formats - WebP, AVIF, JPEG with automatic browser fallback
  • 📉 70-99% Size Reduction - Proven compression ratios from real-world testing

Developer Experience:

  • 📦 Batch Image Processing - Compress multiple images concurrently
  • 📱 HEIC/HEIF Support - Convert iOS images (iPhone photos)
  • 🎨 PNG Transparency - Preserves alpha channels automatically
  • 📊 Upload Progress Tracking - Real-time compression progress callbacks
  • 🔧 TypeScript First - Complete type definitions and IntelliSense
  • 🪶 5.8KB Gzipped - Minimal bundle size, zero dependencies
  • React Hooks - Simple useShrink() hook for React integration

Production Ready:

  • ✅ Works with React, Next.js, Vite, Create React App
  • ✅ Browser image optimization before upload
  • ✅ Automatic format detection (JPEG, PNG, WebP, AVIF, HEIC)
  • ✅ Memory efficient processing
  • ✅ Works on mobile browsers (iOS Safari, Chrome Mobile)

📦 Installation

Install via npm, yarn, or pnpm:

npm install react-shrink
# or
yarn add react-shrink
# or
pnpm add react-shrink

Optional: Add HEIC/HEIF support for iOS iPhone images:

npm install heic2any

Compatible with: React 16.8+, Next.js, Vite, Create React App, Remix, Gatsby

Verify installation:

npm list react-shrink

🚀 Quick Start

React Hook (Recommended)

import { useShrink } from 'react-shrink'

function ImageUploader() {
  const { shrink, isProcessing, progress } = useShrink()

  const handleFile = async (file: File) => {
    const result = await shrink(file, {
      maxKB: 300,  // Target 300KB or less
      maxEdge: 2048 // Max 2048px width/height
    })

    // Upload compressed blob
    await uploadToServer(result.blob)
  }

  return (
    <div>
      <input type="file" accept="image/*" onChange={e => handleFile(e.target.files[0])} />
      {isProcessing && <progress value={progress} max={100} />}
    </div>
  )
}

Standalone Function

import { shrink } from 'react-shrink'

const result = await shrink(imageFile, {
  maxKB: 500,
  codecs: ['webp', 'jpeg']
})

console.log(`Reduced from ${imageFile.size} to ${result.bytes} bytes`)

With Web Workers (Better Performance)

import { shrinkWithWorker } from 'react-shrink'

// Non-blocking compression - UI stays responsive
const result = await shrinkWithWorker(largeFile, { maxKB: 300 })

📖 API

Core Functions

shrink(file, options?)

Main compression function. Runs on main thread.

const result = await shrink(file, {
  maxKB: 300,           // Target max size (KB)
  maxEdge: 2048,        // Max dimension (px)
  codecs: ['webp', 'jpeg'], // Preferred formats
  quality: 0.85,        // Fixed quality or auto
  useWorker: false      // Use web worker
})

Returns: ShrinkResult

{
  blob: Blob          // Compressed image
  bytes: number       // Final size
  width: number       // Final dimensions
  height: number
  mime: string        // Output format
  diagnostics: {
    ratio: number     // Compression ratio
    timeMs: number    // Processing time
    codec: string     // Used codec
    quality: number   // Applied quality
  }
}

shrinkWithWorker(file, options?)

Worker-based compression. Recommended for large files (>2MB).

  • Non-blocking UI
  • 50-80% faster for large images
  • Automatic worker pool management
  • Same API as shrink()

Requires: Chrome 69+, Firefox 105+, Safari 16.4+

shrinkBatch(files, options?)

Process multiple images concurrently.

const result = await shrinkBatch(files, {
  maxKB: 300,
  concurrency: 3,  // Parallel operations
  onProgress: (done, total) => console.log(`${done}/${total}`)
})

console.log(`Processed: ${result.successful}/${result.total}`)

React Hook

useShrink()

Stateful compression with automatic cleanup.

const {
  shrink,              // Compress single file
  shrinkBatch,         // Compress multiple files
  isProcessing,        // Current state
  progress,            // 0-100
  error,               // Last error
  result,              // Last result
  workerSupported,     // Worker availability
  reset                // Clear state
} = useShrink()

Auto-worker: Automatically uses workers for files >2MB when supported.

Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | maxKB | number | 300 | Target max file size (KB) | | maxEdge | number | 2048 | Max width/height (px) | | codecs | ImageCodec[] | ['webp','jpeg'] | Preferred formats | | transparency | 'keep'┃'remove' | 'keep' | Alpha channel handling | | quality | number | auto | Fixed quality 0-1 | | stripMetadata | boolean | true | Remove EXIF data | | useWorker | boolean | auto | Enable web workers | | onProgress | function | - | Progress callback |

Presets

Ready-made configurations for common scenarios:

import { PRESET_AVATAR, PRESET_GALLERY, PRESET_SOCIAL } from 'react-shrink'

await shrink(file, PRESET_AVATAR)  // 100KB, 512px
await shrink(file, PRESET_GALLERY) // 300KB, 2048px
await shrink(file, PRESET_SOCIAL)  // 500KB, 1920px

Available presets:

  • PRESET_THUMBNAIL - 50KB, 200px
  • PRESET_AVATAR - 100KB, 512px
  • PRESET_GALLERY - 300KB, 2048px
  • PRESET_HIGH_QUALITY - 1MB, 4096px
  • PRESET_SOCIAL - 500KB, 1920px
  • PRESET_DOCUMENT - 400KB, 2560px
  • PRESET_ECOMMERCE - 350KB, 2000px

Custom presets:

const custom = createPreset('gallery', { maxKB: 500, codecs: ['avif', 'webp'] })

💡 Examples

Batch Upload

import { useShrink } from 'react-shrink'

function BatchUploader() {
  const { shrinkBatch } = useShrink()

  const handleFiles = async (files: File[]) => {
    const result = await shrinkBatch(files, {
      maxKB: 300,
      concurrency: 3,
      useWorker: true
    })

    console.log(`Saved ${result.totalBytesSaved} bytes`)
  }

  return <input type="file" multiple onChange={e => handleFiles([...e.target.files])} />
}

With Progress Bar

function ProgressExample() {
  const [progress, setProgress] = useState(0)

  const compress = async (file: File) => {
    await shrink(file, {
      maxKB: 300,
      onProgress: setProgress
    })
  }

  return <progress value={progress} max={100} />
}

Error Handling

import { ImageLoadError, CompressionError } from 'react-shrink'

try {
  const result = await shrink(file)
} catch (error) {
  if (error instanceof ImageLoadError) {
    alert('Invalid image file')
  } else if (error instanceof CompressionError) {
    alert('Compression failed')
  }
}

HEIC Support (iOS Photos)

import { shrink } from 'react-shrink'

// Automatic HEIC detection and conversion
const result = await shrink(iphotoFile, { maxKB: 300 })
// Works seamlessly if heic2any is installed

Advanced: Worker Pool

import { getWorkerPool, terminateWorkerPool } from 'react-shrink'

// Access worker pool directly
const pool = await getWorkerPool(4) // 4 workers
console.log(pool.getStats())

// Cleanup when done
terminateWorkerPool()

🧪 Worker Support

Check browser compatibility:

import { canUseWorkerCompression, getOptimalWorkerCount } from 'react-shrink'

if (canUseWorkerCompression()) {
  console.log(`Workers available: ${getOptimalWorkerCount()}`)
}

Browser Requirements:

  • OffscreenCanvas API
  • Transferable ImageBitmap
  • Worker API

Supported:

  • Chrome 69+
  • Firefox 105+
  • Safari 16.4+
  • Edge 79+

🎯 Performance

Real-World Benchmarks

Tested on MacBook Air M2 2022, Chrome browser, WebP compression with maxKB: 300:

| Resolution | Input Size | Output Size | Reduction | Time | |------------|------------|-------------|-----------|------| | 3024×4032 | 1.93 MB | 211 KB | 89% | 699ms | | 4320×4320 | 12.63 MB | 111 KB | 99% | 716ms | | 1024×1024 | 670 KB | 15.7 KB | 98% | 105ms |

🔧 Utilities

Low-level functions for advanced use:

import {
  calculateNewDimensions,
  hasAlphaChannel,
  isCodecSupported,
  getMimeType
} from 'react-shrink'

// Dimension calculations
const { width, height } = calculateNewDimensions(1920, 1080, 1024)

// Codec detection
const avifSupported = await isCodecSupported('avif')

🌐 Browser Support

| Feature | Chrome | Firefox | Safari | Edge | |---------|--------|---------|--------|------| | Core | 60+ | 55+ | 12+ | 79+ | | WebP | 32+ | 65+ | 14+ | 18+ | | AVIF | 85+ | 93+ | 16+ | 93+ | | Workers | 69+ | 105+ | 16.4+ | 79+ |

🛠️ Development

# Install dependencies
npm install

# Run demo
npm run dev

# Build library
npm run build

# Run tests
npm test

# Type check
npm run typecheck

# Lint & format
npm run lint
npm run format

🎯 Use Cases

Perfect for:

  • 📸 Image upload forms - Reduce upload times and server bandwidth
  • 🖼️ Photo galleries - Optimize multiple images before upload
  • 👤 Profile picture uploads - Compress avatars and profile photos
  • 🛒 E-commerce platforms - Product image optimization
  • 📱 Mobile-first apps - Reduce data usage on mobile networks
  • 📝 Content management systems - CMS image optimization
  • 💬 Social media apps - Compress user-generated content
  • 📊 File upload widgets - React file uploader with compression

License

MIT © 2025 Badla Moussaab

Contributing

Contributions are welcome! Help improve React-Shrink:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

🌟 Support

If React-Shrink helps your project:

🔗 Links


⬆ back to top

GitHub stars npm