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

@imerljak/react-cropper-2

v0.1.1

Published

A modern React wrapper for CropperJS 2.x web components

Readme

react-cropper-2

A modern React wrapper for CropperJS 2.x

npm version License: MIT

A TypeScript-first React library that provides idiomatic React bindings for CropperJS 2.x web components.

Features

  • CropperJS 2.x Support - Built for the latest CropperJS web components
  • React 19 Compatible - Full support for React 19.x
  • TypeScript First - Complete type safety with strict mode
  • Three APIs - Component, simplified hook, and advanced hook
  • Modern Architecture - Built on web standards
  • Fully Tested - 96%+ test coverage with 55 passing tests
  • Interactive Docs - Storybook documentation

Why react-cropper-2?

The original react-cropper library only supports CropperJS 1.x. CropperJS 2.x is a complete rewrite using modern web components, requiring new React bindings. This library provides three flexible APIs to work with CropperJS 2.x in React applications.

Installation

npm install @imerljak/react-cropper-2 cropperjs@2

Quick Start

Using the Component (Recommended)

The simplest way to use the library:

import { useRef } from 'react';
import { Cropper, type CropperRef } from '@imerljak/react-cropper-2';

function App() {
  const cropperRef = useRef<CropperRef>(null);

  const handleGetBounds = () => {
    const bounds = cropperRef.current?.getBounds();
    console.log('Crop bounds:', bounds);
  };

  return (
    <div>
      <Cropper
        ref={cropperRef}
        src="/image.jpg"
        alt="Crop me"
        crossOrigin="anonymous"
        aspectRatio={16 / 9}
        onReady={() => console.log('Cropper ready!')}
        onChange={(e) => console.log('Crop changed:', e.detail.bounds)}
      />
      <button onClick={handleGetBounds}>Get Bounds</button>
      <button onClick={() => cropperRef.current?.reset()}>Reset</button>
    </div>
  );
}

Using the Hook

For more control and composition:

import { useCropper } from '@imerljak/react-cropper-2';

function App() {
  const { renderCropper, bounds, reset, clear, getCroppedCanvas } = useCropper({
    src: '/image.jpg',
    alt: 'Crop me',
    crossOrigin: 'anonymous',
    aspectRatio: 16 / 9,
    onReady: () => console.log('Ready!'),
    onChange: (e) => console.log('Changed:', e.detail),
  });

  const handleExport = async () => {
    const canvas = await getCroppedCanvas();
    const url = canvas?.toDataURL('image/png');
    // Use the cropped image
  };

  return (
    <div>
      {renderCropper({ style: { maxHeight: '500px' } })}
      <div>
        {bounds && <pre>{JSON.stringify(bounds, null, 2)}</pre>}
      </div>
      <button onClick={reset}>Reset</button>
      <button onClick={clear}>Clear</button>
      <button onClick={handleExport}>Export</button>
    </div>
  );
}

Advanced Usage

For maximum control, use the advanced hook:

import { useCropperAdvanced } from '@imerljak/react-cropper-2';

function App() {
  const {
    canvasRef,
    selectionRef,
    bounds,
    isReady,
    getBounds,
    setBounds,
    reset,
    getCroppedCanvas,
  } = useCropperAdvanced({
    autoInitialize: true,
    onReady: (canvas) => console.log('Ready!', canvas),
    onChange: (e) => console.log('Changed:', e.detail),
  });

  return (
    <div>
      <cropper-canvas ref={canvasRef} background>
        <cropper-image
          src="/image.jpg"
          alt="Crop me"
          crossorigin="anonymous"
          rotatable
          scalable
          translatable
        />
        <cropper-selection
          ref={selectionRef}
          aspect-ratio={16 / 9}
          initial-coverage={0.8}
          movable
          resizable
          zoomable
          outlined
        >
          <cropper-grid role="grid" bordered covered />
          <cropper-crosshair centered />
          <cropper-handle action="move" theme-color="rgba(255, 255, 255, 0.35)" />
          <cropper-handle action="n-resize" />
          <cropper-handle action="e-resize" />
          <cropper-handle action="s-resize" />
          <cropper-handle action="w-resize" />
          <cropper-handle action="ne-resize" />
          <cropper-handle action="nw-resize" />
          <cropper-handle action="se-resize" />
          <cropper-handle action="sw-resize" />
        </cropper-selection>
      </cropper-canvas>
      <button onClick={() => setBounds({ x: 50, y: 50, width: 200, height: 200 })}>
        Set Custom Bounds
      </button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

API Documentation

<Cropper> Component

Props

| Prop | Type | Description | |------|------|-------------| | src | string | Image URL (required) | | alt | string | Image alt text | | crossOrigin | 'anonymous' \| 'use-credentials' | CORS setting | | aspectRatio | number | Aspect ratio constraint (e.g., 16/9) | | initialCoverage | number | Initial crop coverage (0-1) | | background | boolean | Show background (default: true) | | rotatable | boolean | Enable rotation (default: true) | | scalable | boolean | Enable scaling (default: true) | | translatable | boolean | Enable translation (default: true) | | movable | boolean | Enable moving selection (default: true) | | resizable | boolean | Enable resizing selection (default: true) | | zoomable | boolean | Enable zooming (default: true) | | outlined | boolean | Show selection outline (default: true) | | onReady | (canvas: CropperCanvasElement) => void | Callback when ready | | onChange | CropperEventHandler | Callback when crop changes | | onCropStart | CropperEventHandler | Callback when crop starts | | onCropMove | CropperEventHandler | Callback during crop movement | | onCropEnd | CropperEventHandler | Callback when crop ends |

Ref Methods

interface CropperRef {
  getCanvas: () => CropperCanvasElement | null;
  getBounds: () => CropperBounds | null;
  setBounds: (bounds: Partial<CropperBounds>) => void;
  reset: () => void;
  clear: () => void;
  getCroppedCanvas: (options?) => Promise<HTMLCanvasElement | null>;
}

useCropper Hook

Simplified hook that handles rendering for you.

const {
  renderCropper,
  bounds,
  isReady,
  getBounds,
  setBounds,
  reset,
  clear,
  getCanvas,
  getSelection,
  getCroppedCanvas,
} = useCropper(options);

useCropperAdvanced Hook

Advanced hook for maximum control. You manage rendering yourself.

const {
  canvasRef,
  selectionRef,
  bounds,
  isReady,
  getBounds,
  setBounds,
  reset,
  clear,
  getCanvas,
  getSelection,
  getCroppedCanvas,
} = useCropperAdvanced(options);

Live Examples

Check out the interactive Storybook documentation with live examples for:

  • Basic cropping
  • Different aspect ratios
  • Custom styling
  • Event handling
  • All three API approaches
  • Advanced configurations

Development

# Install dependencies
npm install

# Start example app
npm run dev

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Build library
npm run build

# Start Storybook
npm run storybook

# Build Storybook
npm run build-storybook

Project Structure

react-cropper-2/
├── src/
│   ├── components/
│   │   ├── Cropper.tsx              # Main component
│   │   └── Cropper.test.tsx         # Component tests
│   ├── hooks/
│   │   ├── useCropper.tsx           # Simplified hook
│   │   ├── useCropper.test.ts       # Hook tests
│   │   ├── useCropperAdvanced.ts    # Advanced hook
│   │   └── useCropperAdvanced.test.ts
│   ├── types/
│   │   ├── index.ts                 # TypeScript types
│   │   └── jsx.d.ts                 # JSX declarations
│   ├── stories/                     # Storybook stories
│   └── index.ts                     # Main export
├── examples/basic/                  # Example application
├── tests/setup.ts                   # Test configuration
└── dist/                            # Build output

Requirements

  • React 18.0.0 or higher (works with React 19)
  • CropperJS 2.0.1 or higher
  • TypeScript 5.6+ (for TypeScript projects)

Browser Support

Supports all modern browsers that support:

  • ES2020
  • Web Components (Custom Elements)
  • ES Modules

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

License

MIT © 2025

Acknowledgments

Related Projects