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

@ashutoshmishr0/image-cropper

v1.0.0

Published

A beautiful React image cropper modal. Click to pick a file, crop with drag/zoom/resize, get base64 PNG output. Supports circle, square, and rectangle shapes. Works with Next.js App Router.

Readme

@ashutoshmishr0/image-cropper

A beautiful, zero-dependency React image cropper modal. The user clicks a button, picks an image file, and a smooth modal opens with a full crop interface — drag to pan, zoom slider, resize handles, and shape masks. On confirm, the cropped image is returned as a base64 PNG string directly in the component where it is used.

Works with Next.js App Router, Pages Router, and any React application.


Installation

npm install @ashutoshmishr0/image-cropper

How it works

  1. Wrap any button or element with <ImageCropper> as children
  2. User clicks the element — file picker opens
  3. User selects an image — crop modal opens automatically
  4. User drags, zooms, and adjusts the crop area
  5. User clicks "Crop & Apply" — onCrop is called with the base64 PNG
  6. Modal closes — use the base64 string however you want (preview, upload, etc.)

Basic Usage

"use client";

import { useState } from "react";
import ImageCropper from "@ashutoshmishr0/image-cropper";

export default function Page() {
  const [preview, setPreview] = useState<string | null>(null);

  return (
    <div>
      <ImageCropper onCrop={(base64) => setPreview(base64)} />

      {preview && <img src={preview} alt="Cropped" />}
    </div>
  );
}

Custom Trigger Button

Pass any element as children. Clicking it will open the file picker.

<ImageCropper onCrop={(base64) => setPreview(base64)}>
  <button className="your-own-button">Upload Photo</button>
</ImageCropper>

Examples

Avatar crop (circle, fixed 200x200 output)

<ImageCropper
  shape="circle"
  outputWidth={200}
  outputHeight={200}
  onCrop={(base64) => setAvatar(base64)}
>
  <img
    src={avatar || "/default-avatar.png"}
    style={{ width: 80, height: 80, borderRadius: "50%", cursor: "pointer" }}
    alt="Click to change avatar"
  />
</ImageCropper>

Banner crop (16:9, fixed 1200x675 output)

<ImageCropper
  shape="rect"
  aspectRatio={16 / 9}
  outputWidth={1200}
  outputHeight={675}
  onCrop={(base64) => setBanner(base64)}
>
  <button>Upload Banner</button>
</ImageCropper>

Square crop

<ImageCropper
  shape="square"
  outputWidth={500}
  outputHeight={500}
  onCrop={(base64) => setImage(base64)}
>
  <button>Upload Photo</button>
</ImageCropper>

Free crop — no fixed ratio or size

When outputWidth, outputHeight, and aspectRatio are all omitted, the user can resize freely in any direction.

<ImageCropper
  onCrop={(base64, cropArea) => {
    console.log(base64);
    console.log(cropArea); // { x, y, width, height } in natural image pixels
  }}
>
  <button>Choose Image</button>
</ImageCropper>

Open programmatically using ref

"use client";

import { useRef } from "react";
import ImageCropper, { type ImageCropperRef } from "@ashutoshmishr0/image-cropper";

export default function Page() {
  const cropperRef = useRef<ImageCropperRef>(null);

  return (
    <>
      <button onClick={() => cropperRef.current?.open()}>
        Open Cropper
      </button>

      <ImageCropper
        ref={cropperRef}
        onCrop={(base64) => console.log(base64)}
      />
    </>
  );
}

Upload cropped image to server

<ImageCropper
  shape="circle"
  outputWidth={300}
  outputHeight={300}
  onCrop={async (base64) => {
    const blob = await fetch(base64).then((r) => r.blob());
    const formData = new FormData();
    formData.append("avatar", blob, "avatar.png");
    await fetch("/api/upload", { method: "POST", body: formData });
  }}
>
  <button>Upload Avatar</button>
</ImageCropper>

All Props

| Prop | Type | Default | Description | |---|---|---|---| | onCrop | (base64: string, cropArea: CropArea) => void | required | Called when the user confirms the crop | | children | ReactNode | undefined | Any clickable element that triggers the file picker. If omitted, a default "Choose Image" button is shown. | | shape | "rect" / "circle" / "square" | "rect" | Shape of the crop mask | | outputWidth | number | undefined | Output width in pixels. Locks aspect ratio when combined with outputHeight. | | outputHeight | number | undefined | Output height in pixels | | aspectRatio | number | undefined | Lock crop ratio without fixing output size. Example: 16/9. Ignored when outputWidth and outputHeight are both set. | | cropperWidth | number | 520 | Width of the crop canvas inside the modal | | cropperHeight | number | 420 | Height of the crop canvas inside the modal | | minCropWidth | number | 40 | Minimum crop box width in screen pixels | | minCropHeight | number | 40 | Minimum crop box height in screen pixels | | showGrid | boolean | true | Show rule-of-thirds grid lines inside the crop area | | showZoom | boolean | true | Show the zoom slider | | borderRadius | string | "0px" | Border radius of the crop box. Only applies when shape is "rect". | | confirmLabel | string | "Crop & Apply" | Label for the confirm button | | cancelLabel | string | "Cancel" | Label for the cancel button | | accept | string | "image/*" | Accepted file types for the file picker | | triggerClassName | string | "" | CSS class applied to the trigger wrapper |


Ref Methods

interface ImageCropperRef {
  open: () => void; // Programmatically open the file picker
}

CropArea Object

The second argument in onCrop contains the crop coordinates in natural image pixels (not screen pixels).

interface CropArea {
  x: number;       // left position in original image
  y: number;       // top position in original image
  width: number;   // width of cropped region
  height: number;  // height of cropped region
}

TypeScript Imports

import ImageCropper from "@ashutoshmishr0/image-cropper";
import type { ImageCropperProps, ImageCropperRef, CropArea, CropShape } from "@ashutoshmishr0/image-cropper";

Notes for Next.js

Add "use client" at the top of any file that uses this component.

"use client";
import ImageCropper from "@ashutoshmishr0/image-cropper";

The component uses browser APIs — canvas, pointer events, FileReader. It is a client-only component and must not be rendered on the server.


License

MIT