Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

ImageCropper

  • Needs review
  • RTL

Shows an image with a crop frame people drag to move and resize, free or locked to an aspect ratio, in a rectangle or a circle, with a live CSS filter preview. No Figma frame: built from the approved Studio, Darkroom and Guided samples, which are its stories. The component only edits the frame; picking files, filter controls and saving stay in your app. Read the frame from onCropChange and export it with cropImage(src, crop, { filter, shape, type }), which returns a Blob. Keyboard (WCAG 2.1.1): the frame is one tab stop; arrow keys move it, Alt + arrow keys resize it, Shift makes 10× steps. The instructions are its accessible description. Resizing by dragging is also possible from the keyboard, so no action depends on dragging alone (2.5.7). Handles have a 36 px hit area. Consumer duties: an upload button (FileTrigger or Dropzone) next to the stage, a visible output size if it matters, file type and size checks, and an error message for onError.

import { ImageCropper } from "@nexera-ui/react";
Loading example…
4
examples
18
props
4
live controls
1
platform
0
WCAG criteria
3
blocks use it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
shape
handles
grid
label
Generated code
import { ImageCropper } from "@nexera-ui/react";

<ImageCropper />

Examples 3

The same examples as Storybook, rendered live. Open Code to copy one.

Studio

Sample A, Studio: an editor with the image beside an inspector. Crop has nine ratios and the exact frame in pixels, Filters has eight looks, Adjust has three sliders, and the footer picks the file format with a Select and saves. Upload, or drop an image on the stage, to edit your own.

Loading example…

Darkroom

Sample B, Darkroom: the photo fills a dark stage (a data-theme="dark" wrapper, so every Nexera part inside turns dark) with bracket handles and a thirds grid. One tool shows at a time in the tray, picked from the tab bar at the bottom: ratio chips, a filter strip, or one slider for the chosen adjustment. Save exports a JPEG.

Loading example…

Guided

Sample C, Guided: a compact card in three steps (Step). Upload with a Dropzone, crop in a circle or square frame with SegmentedControls, then finish with a preview, filters, adjustments and the file format, and save. It opens on the crop step with the sample photo; Back returns to the upload step.

Loading example…

Props 18

Press "Try it" on a card to load that prop into the playground.

18 props shown

src*Nexera
string | null | undefined

The image: an object URL from a picked file (URL.createObjectURL(file)), a data: URL, or a same-origin URL. Images from other origins need CORS headers, or cropImage cannot export them. null shows fallback.

Default –
altNexera
string

Text alternative of the image. Leave empty when the surrounding UI already names it (a file name, a heading).

Default
aspectRatioNexera
number | null

Width divided by height of the frame, for example 1, 16 / 9 or 4 / 5. null lets people drag each edge freely. Changing it re-fits the frame. Only corner handles show while a ratio is set.

Default null
shapeNexera
"rect" | "circle"

Frame shape. "circle" shows a round frame for avatars; pair it with aspectRatio={1} and pass the same shape to cropImage.

Default rect
handlesNexera
"square" | "bracket" | "dot"

Look of the resize handles: square (Studio sample), bracket (Darkroom, for dark stages) or dot (Guided).

Default square
gridNexera
"dragging" | "always" | "never"

When the rule-of-thirds grid shows inside the frame.

Default dragging
filterNexera
string

CSS filter previewed on the image, for example a preset from IMAGE_FILTERS combined with composeImageFilter. Pass the same value to cropImage so the saved file matches.

Default none
defaultCropNexera
CropArea

Starting frame in natural image pixels, for example the crop saved last time. Otherwise the frame is fitted and centred.

Default –
onCropChangeNexera
(crop: CropArea) => void

Called with the frame in natural image pixels after every move, resize, ratio change or new image.

Default –
onLoadNexera
(size: ImageSize) => void

Called with the natural size once the image has loaded.

Default –
onErrorNexera
() => void

Called when the image cannot be loaded or decoded. Show an error and let people pick another file.

Default –
onFileDropNexera
(file: File) => void

Called with the first file dropped on the stage; also turns the stage into a drop target. Check the file type and size yourself. Dropping is an enhancement: always offer a button that opens the file picker too (WCAG 2.5.7).

Default –
labelNexera
string

Accessible name of the crop frame. Translate it.

Default Crop frame
instructionsNexera
string

How to use the frame without a pointer, read after its name. Translate it.

Default Drag to move it, or drag a handle to resize. Arrow keys move it, Alt with arrow keys resizes it, and Shift makes bigger steps.
dropLabelNexera
string

Message over the stage while a file is dragged over it (onFileDrop). Translate it.

Default Drop to replace the image
fallbackNexera
ReactNode

Content shown while there is no src, such as an empty state with an upload button.

Default –
classNameNexera
string

Extra classes for the root (the stage), merged last. Set the height here (default h-80); bg-media-bg makes it dark.

Default –
styleNexera
CSSProperties

Inline style of the root.

Default –

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

Keyboard support
KeyAction
TabMoves focus to the crop frame (one tab stop)
Arrow keysMove the frame one screen pixel
Alt + arrow keysResize the frame from its bottom-right corner; with a ratio, both sides follow
ShiftMakes each step 10 pixels, for moving or resizing
  • The frame is a focusable group named by `label` and described by `instructions`, so screen reader users hear how to move and resize it. Translate both.
  • Everything a drag does can be done from the keyboard (WCAG 2.1.1, 2.5.7). Handles have a 36 px hit area.
  • Dropping a file on the stage is an extra. Always offer a button that opens the file picker too (FileTrigger or Dropzone).
  • The crop is reported in natural image pixels, so it does not depend on the size the image is shown at.
  • cropImage bakes in the same filter the preview shows, also in Safari, where it applies the colour maths to the pixels.

This component relies on the shared primitives' accessibility tests; no criteria are tagged to it directly yet.

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

Usage
<ImageCropper className="shadow-sm" />

Do and don't

DoShow the output size and let people pick the format with a Select.

Don'tHide the result's size or save at screen resolution.

DoUse the circle frame with aspectRatio 1 for avatars, and pass the same shape to cropImage.

Don'tCrop a circle on screen but save a square with corners people never saw.

DoCheck the file type and size before showing it, and say how to fix a bad file.

Don'tPass any dropped file straight to src.

Used in blocks

Related components