Skip to main content
Version: Latest

React Image Editor

The official @unlayer/react-image-editor component loads the standalone Image Editor, mounts it into your React application, and cleans it up when the component unmounts. It requires React 18 or later and Node.js 18 or later.

The component and manual editing tools are free. The optional AI Assistant is a paid feature.

Installation

npm install @unlayer/react-image-editor

Basic Usage

src/ImageEditorComponent.tsx
import { useRef } from 'react';
import ImageEditor, {
type ImageEditorRef,
type ImageEditorSaveResult,
} from '@unlayer/react-image-editor';

export default function ImageEditorComponent() {
const imageEditorRef = useRef<ImageEditorRef>(null);

const saveImage = async ({ blob }: ImageEditorSaveResult) => {
const formData = new FormData();
formData.append('file', blob, 'edited.png');

await fetch('/api/images', {
method: 'POST',
body: formData,
});
};

return (
<ImageEditor
ref={imageEditorRef}
image="https://example.com/photo.jpg"
minHeight="700px"
options={{
projectId: 1234, // Replace with your Unlayer Project ID
theme: 'light',
}}
onSave={saveImage}
onCancel={() => {
// Close your image editor view
}}
onLoadError={() => {
// The image could not be loaded because of CORS, a 404, or a decode error
}}
onError={(error) => {
// The embed script or editor instance could not be loaded
console.error('Image Editor failed:', error);
}}
/>
);
}

The image prop accepts an image URL or base64 data URL. The save result contains both a dataUrl for previews or inline use and a blob that is ready to upload.

Unlayer's image editor open over a selected image, with a right-docked tool rail (Filter, Crop, Resize, Draw, Text, Shapes, Stickers, Frame) and the Filter properties panel showing one-tap preset thumbnails and adjustment slidersUnlayer's image editor open over a selected image, with a right-docked tool rail (Filter, Crop, Resize, Draw, Text, Shapes, Stickers, Frame) and the Filter properties panel showing one-tap preset thumbnails and adjustment sliders

Configuration

Pass standalone Image Editor configuration through options:

<ImageEditor
image={imageUrl}
options={{
projectId: 1234,
theme: 'dark',
locale: 'fr',
features: {
imageEditor: {
tools: {
draw: false,
stickers: false,
},
},
ai: {
enabled: true,
assistant: true,
},
},
}}
/>
Newer Image Editor options

Newer editor builds also support features.imageEditor.dock and features.imageEditor.tools.corners. These fields type-check once your installed @unlayer/types version includes them.

See Configuration for tools, icons, theme, and localization, and AI Assistant for AI setup.

Props

NameTypeDescriptionDefault
imagestringImage URL or base64 data URL to edit. Required.
optionsImageEditorOptionsStandalone editor options such as projectId, features, theme, locale, and translations.{}
editorIdstringID applied to the container element. The editor mounts by element reference, so this is primarily cosmetic.
minHeightnumber | stringMinimum height of the outer editor container.500
styleReact.CSSPropertiesInline styles applied to the inner editor container.{}
scriptUrlstringAdvanced override for the image-editor embed script URL. Use one script URL across all instances on a page.CDN URL
onLoad(editor) => voidCalled with the editor instance after it mounts.
onSave(result) => voidCalled with { dataUrl, blob } when the user saves.
onCancel() => voidCalled when the user cancels editing.
onLoadError() => voidCalled when the image fails to load into the canvas.
onError(error: Error) => voidCalled when the script, editor creation, or an image reset fails.

onLoadError and onError cover different failures: use onLoadError for an image that cannot be decoded or fetched, and onError for wrapper-level loading or lifecycle failures.

Editor Instance

The forwarded ref exposes { editor }. It is null until the editor mounts:

const dataUrl = imageEditorRef.current?.editor?.getImage();
const hasUnsavedChanges = imageEditorRef.current?.editor?.hasChanges() ?? false;

await imageEditorRef.current?.editor?.reset(nextImageUrl);
imageEditorRef.current?.editor?.updateOptions({ theme: 'dark' });
MethodDescription
getImage()Returns the flattened canvas as a data URL, or null.
hasChanges()Returns whether the editor has unsaved edits.
reset(imageUrl?)Clears history and AI chat, and optionally loads another image.
updateOptions(options)Updates editor options at runtime.
destroy()Unmounts the editor. React calls this automatically when the component unmounts.

Updating Props

The wrapper applies prop changes according to their impact:

ChangeBehavior
imageCalls reset(newImage) and clears undo/redo history and AI chat.
options.theme, locale, or translationsCalls updateOptions() without remounting, preserving editor state.
Any other options valueDestroys and recreates the editor, discarding unsaved changes.
scriptUrlRemounts the editor; do not mix URLs because the page's first installed embed wins globally.
Callback propsUses the latest callback without remounting.

Rapid image changes are serialized and collapse to the latest value, so an earlier image load cannot overwrite a newer one.

Next.js and React Server Components

The package ships as a client component and only accesses the DOM from effects, so it can be imported directly in Next.js App Router and other React Server Components environments.

For a complete runnable example, see the react-image-editor demo.