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-crop-kit

v1.2.0

Published

Responsive image and video crop component for React 19 — drag, resize, fixed aspect ratio, circular mask, and keyboard controls.

Readme

react-crop-kit

npm version license

A responsive image and video crop component for React 19. Drag to draw, resize with handles, nudge with the keyboard, and keep the selection in pixels or percentages.

Install

pnpm add react-crop-kit
# or npm install react-crop-kit / yarn add react-crop-kit

Peer dependencies: react and react-dom (^19).

Setup

Import the component — default styles are injected automatically at runtime:

import { ReactCropKit } from "react-crop-kit";

Basic usage

ReactCropKit is controlled: pass crop from state and update it in onChange.

import { useState } from "react";
import { ReactCropKit, type Crop } from "react-crop-kit";

function ImageCropper({ src }: { src: string }) {
  const [crop, setCrop] = useState<Crop>();

  return (
    <ReactCropKit
      crop={crop}
      onChange={(_pixelCrop, percentCrop) => setCrop(percentCrop)}
    >
      <img src={src} alt="Crop me" />
    </ReactCropKit>
  );
}

onChange receives two shapes:

  • PixelCropunit: "px", useful for canvas export
  • PercentCropunit: "%", scales when the media is resized

Storing the percent crop in state (as above) is the usual choice.

Fixed aspect ratio

Pass aspect (width ÷ height). Examples: 1 for a square, 16 / 9 for landscape.

<ReactCropKit
  aspect={16 / 9}
  crop={crop}
  onChange={(_pixel, percent) => setCrop(percent)}
>
  <img src={src} alt="" />
</ReactCropKit>

Initial crop

When you set crop for the first time (e.g. after load), onComplete runs once if it was previously unset — handy for previews.

Helpers centerCrop and makeAspectCrop (plus convertToPercentCrop / convertToPixelCrop) ship from the same package:

import {
  ReactCropKit,
  centerCrop,
  makeAspectCrop,
  type Crop,
} from "react-crop-kit";

function onImageLoad(e: React.SyntheticEvent<HTMLImageElement>) {
  const { width, height } = e.currentTarget;
  setCrop(
    centerCrop(
      makeAspectCrop({ unit: "%", width: 90 }, 16 / 9, width, height),
      width,
      height,
    ),
  );
}

Or set a crop manually:

const [crop, setCrop] = useState<Crop>({
  unit: "%",
  x: 10,
  y: 10,
  width: 80,
  height: 80,
});

<ReactCropKit
  crop={crop}
  onChange={(_, percent) => setCrop(percent)}
  onComplete={(pixel, percent) => {
    console.log("Ready", pixel, percent);
  }}
>
  <img src={src} alt="" />
</ReactCropKit>

All of x, y, width, and height are required on the crop object when you use one (except you may omit aspect on the prop).

Props

| Prop | Type | Description | |------|------|-------------| | crop | Crop | Controlled selection. Omit to hide the crop UI. | | onChange | (pixel, percent) => void | Required. Called on every change. | | onComplete | (pixel, percent) => void | After drag, resize, or keyboard nudge ends. | | onDragStart | (e: PointerEvent) => void | First pointer move after press. | | onDragEnd | (e: PointerEvent) => void | Pointer up after drag or resize. | | aspect | number | Lock aspect ratio (e.g. 1, 16/9). | | circularCrop | boolean | Circular mask (oval if aspect ≠ 1). | | ruleOfThirds | boolean | Show rule-of-thirds guides. | | disabled | boolean | No interaction; adds ReactCropKit--disabled. | | locked | boolean | No new crop or resize; can still drag selection. | | keepSelection | boolean | Clicking outside does not clear the crop. | | minWidth / minHeight | number | Minimum size in pixels. | | maxWidth / maxHeight | number | Maximum size in pixels. | | className | string | Extra class on the root element. | | styles | CSSProperties | Inline styles on the root. | | ariaLabels | object | Override default English a11y strings. | | renderSelectionAddon | (state) => ReactNode | Custom overlay inside the selection. |

ReactCropKitState passed to renderSelectionAddon:

  • cropIsActive — user is dragging or resizing
  • newCropIsBeingDrawn — drawing a new region

Keyboard

Focus the crop area or a handle, then:

| Keys | Action | |------|--------| | Arrow keys | Move crop or resize from focused handle | | Shift + arrows | 10px step | | Ctrl/Cmd + arrows | 100px step |

Styling

Styles ship with the bundle and are applied when you import react-crop-kit (no separate CSS import required). To load styles as a static stylesheet instead — for example in SSR or when your bundler strips runtime injection — import react-crop-kit/styles.css explicitly.

Override defaults via your own CSS targeting classes such as:

  • .ReactCropKit
  • .ReactCropKit__crop-selection
  • .ReactCropKit--disabled, .ReactCropKit--locked, .ReactCropKit--circular-crop

CSS variables on :root:

  • --rck-drag-handle-size
  • --rck-drag-handle-mobile-size
  • --rck-border-color
  • --rck-focus-color

Exporting the cropped image

Use the pixel crop from onChange / onComplete with a canvas:

function cropImage(
  image: HTMLImageElement,
  pixelCrop: { x: number; y: number; width: number; height: number },
): Promise<Blob> {
  const canvas = document.createElement("canvas");
  const scaleX = image.naturalWidth / image.width;
  const scaleY = image.naturalHeight / image.height;

  canvas.width = pixelCrop.width * scaleX;
  canvas.height = pixelCrop.height * scaleY;

  const ctx = canvas.getContext("2d")!;
  ctx.drawImage(
    image,
    pixelCrop.x * scaleX,
    pixelCrop.y * scaleY,
    pixelCrop.width * scaleX,
    pixelCrop.height * scaleY,
    0,
    0,
    canvas.width,
    canvas.height,
  );

  return new Promise((resolve) =>
    canvas.toBlob((blob) => resolve(blob!), "image/png"),
  );
}

Scale by naturalWidth / width when the displayed image is scaled (responsive layouts).

Development

pnpm install
pnpm run build      # dist/
pnpm run typecheck
pnpm run dev        # watch build

License

MIT © Sunil Nune