Ballmac UI home

Image Cropper

Crop a picture under a fixed frame: drag to move, wheel, pinch or slider to zoom, straighten and turn by quarters, any aspect ratio or a round avatar, full keyboard control and a canvas export to a file.

Loading the picture

Arrow keys move the picture. Plus and minus zoom. The square brackets turn it a quarter. Zero resets.

The result appears here.

Installation

$ pnpm dlx shadcn@latest add @ballmac/image-cropper

Usage

import { ImageCropper } from "@/components/ballmac/image-cropper"

The full example is in the Code tab above.

Examples

Choose the shape

Loading the picture

Arrow keys move the picture. Plus and minus zoom. The square brackets turn it a quarter. Zero resets.

Round avatar from a file

Loading the picture

Arrow keys move the picture. Plus and minus zoom. The square brackets turn it a quarter. Zero resets.

Controlled, with the area

Loading the picture

Arrow keys move the picture. Plus and minus zoom. The square brackets turn it a quarter. Zero resets.

Zoom
1.60×
Turn
8.0°
Area
–
From
–

Loading

Loading the picture

Arrow keys move the picture. Plus and minus zoom. The square brackets turn it a quarter. Zero resets.

Could not load

Loading the picture

Arrow keys move the picture. Plus and minus zoom. The square brackets turn it a quarter. Zero resets.

API reference

PropTypeDefault
src*

The picture: a web address or an object URL.

string—
aspect

Width divided by height of the frame: 1 for a square, 16 / 9 for a banner.

number1
shape

A round frame shows what a round avatar will keep.

"rect" | "round""rect"
valueCrop—
defaultValuePartial<Crop>—
onCropChange(crop: Crop) => void—
onCropComplete

Called when a drag, a key press or a slider move ends, with the crop in pixels of the original.

(result: CropResult) => void—
maxZoom

Zoom the picture can reach.

number4
height

Height of the picture area.

number320
grid

Show thirds lines over the frame.

booleantrue
zoomOnWheel

Zoom with the mouse wheel. Off if the cropper sits in a page people scroll through.

booleantrue
controls

Hide the zoom, straighten and rotate controls, to place your own.

booleantrue
alt

Written for a screen reader: what the picture shows.

string—
crossOrigin

`crossorigin` for the picture. Needed to export one from another site.

"anonymous" | "use-credentials" | """anonymous"
onError(error: Error) => void—
cropperRef

Gives you `toBlob`, `getCrop` and `reset`.

React.Ref<ImageCropperHandle>—

Also accepts the standard attributes of its root element.

Accessibility

KeyAction
Arrow keysMove the picture under the frame; Shift moves it further
+ / -Zoom in and out; the zoom is announced
[ / ]Turn a quarter left or right
0Reset
Sliders and buttonsZoom and straighten are native range inputs with spoken values; turn and reset are buttons

Quality scorecard

8/8

Every applicable check passes

Measured in Chromium 153.0.8010.12 on October 19, 2026, on version 1.0.0, across 6 examples.

How we measure
  • Passed: Accessibility scan

    No serious or critical issues in light and dark, on a phone and a desktop (axe-core 4.13.0, WCAG 2.1 AA and best-practice rules).

  • Passed: Small screens

    No sideways scrolling at 360, 390 or 1280 px wide.

  • Passed: Reduced motion

    Every endless animation stops when the visitor asks for less motion.

  • Passed: Right to left

    Mirrors correctly in Arabic, Hebrew, Persian and Urdu layouts (0% of elements off the mirror, limit 15%).

  • Passed: Clean console

    No console errors or React hydration errors while loading.

  • Passed: Keyboard

    33 tab stops, each showing a visible change when it takes focus. 5 documented keys.

  • Passed: Loading, empty and error

    Ships loading, error states, each with an example.

  • Passed: Automated tests

    Covered by image-cropper.test.tsx.

  • For information: Footprint

    7.1 KB of source (gzip) in 1 file. Installs lucide-react.

Automated checks find a subset of problems and do not replace testing with a screen reader and a keyboard in your own app. What they miss.

Use with AI

<ImageCropper src aspect={1} cropperRef={ref} />. Get the file with await ref.current.toBlob({ width, type }); onCropComplete gives the area in original pixels to crop on a server. shape="round" for avatars. With the shadcn MCP server set up (guide), ask your agent:

Add the Ballmac UI Image Cropper (@ballmac/image-cropper) to this project with the shadcn MCP, then use it where it fits.

Use it for

  • Profile pictures, cover images and product photos cropped before upload
  • Any upload that needs a fixed aspect ratio
  • Straightening a slightly tilted photo

Not for

  • Free-form selection boxes with resizable handles
  • Photo editing with filters, text or drawing
  • Pictures from another site without CORS headers, which cannot be exported

Registry JSON: https://ui.ballmac.com/r/image-cropper.json

Credits

Free to use in personal and commercial projects.

Ballmac UI Pro

Need the whole screen, not one piece?

150 premium blocks (dashboards, settings, calendars, mail, shops, onboarding), a private shadcn registry and Figma tokens. Blocks that show data come with loading, empty and error states built in.

Not ready? Try three Pro blocks free

Leave your email and the blocks appear right here, ready to copy. Yours to use in any project.